Merge "X86_64: Add allocation entrypoint switching for CC is_marking"
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..9902628 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)
@@ -114,10 +116,14 @@
ART_GTEST_dex2oat_environment_tests_HOST_DEPS := \
$(HOST_CORE_IMAGE_optimizing_pic_64) \
$(HOST_CORE_IMAGE_optimizing_pic_32) \
+ $(HOST_CORE_IMAGE_optimizing_no-pic_64) \
+ $(HOST_CORE_IMAGE_optimizing_no-pic_32) \
$(HOST_OUT_EXECUTABLES)/patchoatd
ART_GTEST_dex2oat_environment_tests_TARGET_DEPS := \
$(TARGET_CORE_IMAGE_optimizing_pic_64) \
$(TARGET_CORE_IMAGE_optimizing_pic_32) \
+ $(TARGET_CORE_IMAGE_optimizing_no-pic_64) \
+ $(TARGET_CORE_IMAGE_optimizing_no-pic_32) \
$(TARGET_OUT_EXECUTABLES)/patchoatd
ART_GTEST_oat_file_assistant_test_HOST_DEPS := \
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..b883e08 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",
@@ -52,6 +53,7 @@
"optimizing/code_generator_utils.cc",
"optimizing/constant_folding.cc",
"optimizing/dead_code_elimination.cc",
+ "optimizing/escape.cc",
"optimizing/graph_checker.cc",
"optimizing/graph_visualizer.cc",
"optimizing/gvn.cc",
@@ -253,7 +255,10 @@
},
},
},
- shared_libs: ["libart"],
+ shared_libs: [
+ "libart",
+ "libart-dexlayout",
+ ],
}
art_cc_library {
@@ -290,7 +295,10 @@
},
},
},
- shared_libs: ["libartd"],
+ shared_libs: [
+ "libartd",
+ "libartd-dexlayout"
+ ],
}
art_cc_library {
@@ -312,6 +320,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/compiled_method.h b/compiler/compiled_method.h
index 99b0ac1..174e85e 100644
--- a/compiler/compiled_method.h
+++ b/compiler/compiled_method.h
@@ -26,6 +26,7 @@
#include "base/array_ref.h"
#include "base/bit_utils.h"
#include "base/length_prefixed_array.h"
+#include "dex_file_types.h"
#include "method_reference.h"
namespace art {
@@ -302,9 +303,9 @@
return target_dex_file_;
}
- uint32_t TargetTypeIndex() const {
+ dex::TypeIndex TargetTypeIndex() const {
DCHECK(patch_type_ == Type::kType || patch_type_ == Type::kTypeRelative);
- return type_idx_;
+ return dex::TypeIndex(type_idx_);
}
const DexFile* TargetStringDexFile() const {
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/dex/verification_results.cc b/compiler/dex/verification_results.cc
index 511a787..3fb10d8 100644
--- a/compiler/dex/verification_results.cc
+++ b/compiler/dex/verification_results.cc
@@ -31,49 +31,68 @@
VerificationResults::VerificationResults(const CompilerOptions* compiler_options)
: compiler_options_(compiler_options),
verified_methods_lock_("compiler verified methods lock"),
- verified_methods_(),
- rejected_classes_lock_("compiler rejected classes lock"),
- rejected_classes_() {
-}
+ rejected_classes_lock_("compiler rejected classes lock") {}
VerificationResults::~VerificationResults() {
- Thread* self = Thread::Current();
- {
- WriterMutexLock mu(self, verified_methods_lock_);
- STLDeleteValues(&verified_methods_);
- }
+ WriterMutexLock mu(Thread::Current(), verified_methods_lock_);
+ DeleteResults(preregistered_dex_files_);
+ STLDeleteValues(&verified_methods_);
}
void VerificationResults::ProcessVerifiedMethod(verifier::MethodVerifier* method_verifier) {
DCHECK(method_verifier != nullptr);
MethodReference ref = method_verifier->GetMethodReference();
bool compile = IsCandidateForCompilation(ref, method_verifier->GetAccessFlags());
- const VerifiedMethod* verified_method = VerifiedMethod::Create(method_verifier, compile);
+ std::unique_ptr<const VerifiedMethod> verified_method(
+ VerifiedMethod::Create(method_verifier, compile));
if (verified_method == nullptr) {
// We'll punt this later.
return;
}
-
- WriterMutexLock mu(Thread::Current(), verified_methods_lock_);
- auto it = verified_methods_.find(ref);
- if (it != verified_methods_.end()) {
+ bool inserted;
+ DexFileMethodArray* const array = GetMethodArray(ref.dex_file);
+ const VerifiedMethod* existing = nullptr;
+ if (array != nullptr) {
+ DCHECK(array != nullptr);
+ Atomic<const VerifiedMethod*>* slot = &(*array)[ref.dex_method_index];
+ inserted = slot->CompareExchangeStrongSequentiallyConsistent(nullptr, verified_method.get());
+ if (!inserted) {
+ existing = slot->LoadSequentiallyConsistent();
+ DCHECK_NE(verified_method.get(), existing);
+ }
+ } else {
+ WriterMutexLock mu(Thread::Current(), verified_methods_lock_);
+ auto it = verified_methods_.find(ref);
+ inserted = it == verified_methods_.end();
+ if (inserted) {
+ verified_methods_.Put(ref, verified_method.get());
+ DCHECK(verified_methods_.find(ref) != verified_methods_.end());
+ } else {
+ existing = it->second;
+ }
+ }
+ if (inserted) {
+ // Successfully added, release the unique_ptr since we no longer have ownership.
+ DCHECK_EQ(GetVerifiedMethod(ref), verified_method.get());
+ verified_method.release();
+ } else {
// TODO: Investigate why are we doing the work again for this method and try to avoid it.
LOG(WARNING) << "Method processed more than once: " << ref.PrettyMethod();
if (!Runtime::Current()->UseJitCompilation()) {
- DCHECK_EQ(it->second->GetDevirtMap().size(), verified_method->GetDevirtMap().size());
- DCHECK_EQ(it->second->GetSafeCastSet().size(), verified_method->GetSafeCastSet().size());
+ DCHECK_EQ(existing->GetDevirtMap().size(), verified_method->GetDevirtMap().size());
+ DCHECK_EQ(existing->GetSafeCastSet().size(), verified_method->GetSafeCastSet().size());
}
- // Delete the new verified method since there was already an existing one registered. It
- // is unsafe to replace the existing one since the JIT may be using it to generate a
- // native GC map.
- delete verified_method;
- return;
+ // Let the unique_ptr delete the new verified method since there was already an existing one
+ // registered. It is unsafe to replace the existing one since the JIT may be using it to
+ // generate a native GC map.
}
- verified_methods_.Put(ref, verified_method);
- DCHECK(verified_methods_.find(ref) != verified_methods_.end());
}
const VerifiedMethod* VerificationResults::GetVerifiedMethod(MethodReference ref) {
+ DexFileMethodArray* array = GetMethodArray(ref.dex_file);
+ if (array != nullptr) {
+ return (*array)[ref.dex_method_index].LoadRelaxed();
+ }
ReaderMutexLock mu(Thread::Current(), verified_methods_lock_);
auto it = verified_methods_.find(ref);
return (it != verified_methods_.end()) ? it->second : nullptr;
@@ -105,4 +124,42 @@
return true;
}
+void VerificationResults::PreRegisterDexFile(const DexFile* dex_file) {
+ CHECK(preregistered_dex_files_.find(dex_file) == preregistered_dex_files_.end())
+ << dex_file->GetLocation();
+ DexFileMethodArray array(dex_file->NumMethodIds());
+ WriterMutexLock mu(Thread::Current(), verified_methods_lock_);
+ // There can be some verified methods that are already registered for the dex_file since we set
+ // up well known classes earlier. Remove these and put them in the array so that we don't
+ // accidentally miss seeing them.
+ for (auto it = verified_methods_.begin(); it != verified_methods_.end(); ) {
+ MethodReference ref = it->first;
+ if (ref.dex_file == dex_file) {
+ array[ref.dex_method_index].StoreSequentiallyConsistent(it->second);
+ it = verified_methods_.erase(it);
+ } else {
+ ++it;
+ }
+ }
+ preregistered_dex_files_.emplace(dex_file, std::move(array));
+}
+
+void VerificationResults::DeleteResults(DexFileResults& array) {
+ for (auto& pair : array) {
+ for (Atomic<const VerifiedMethod*>& method : pair.second) {
+ delete method.LoadSequentiallyConsistent();
+ }
+ }
+ array.clear();
+}
+
+VerificationResults::DexFileMethodArray* VerificationResults::GetMethodArray(
+ const DexFile* dex_file) {
+ auto it = preregistered_dex_files_.find(dex_file);
+ if (it != preregistered_dex_files_.end()) {
+ return &it->second;
+ }
+ return nullptr;
+}
+
} // namespace art
diff --git a/compiler/dex/verification_results.h b/compiler/dex/verification_results.h
index 6afd1ab..b3356e0 100644
--- a/compiler/dex/verification_results.h
+++ b/compiler/dex/verification_results.h
@@ -19,8 +19,8 @@
#include <stdint.h>
#include <set>
-#include <vector>
+#include "base/dchecked_vector.h"
#include "base/macros.h"
#include "base/mutex.h"
#include "class_reference.h"
@@ -38,35 +38,48 @@
// Used by CompilerCallbacks to track verification information from the Runtime.
class VerificationResults {
- public:
- explicit VerificationResults(const CompilerOptions* compiler_options);
- ~VerificationResults();
+ public:
+ explicit VerificationResults(const CompilerOptions* compiler_options);
+ ~VerificationResults();
- void ProcessVerifiedMethod(verifier::MethodVerifier* method_verifier)
- REQUIRES_SHARED(Locks::mutator_lock_)
- REQUIRES(!verified_methods_lock_);
+ void ProcessVerifiedMethod(verifier::MethodVerifier* method_verifier)
+ REQUIRES_SHARED(Locks::mutator_lock_)
+ REQUIRES(!verified_methods_lock_);
- const VerifiedMethod* GetVerifiedMethod(MethodReference ref)
- REQUIRES(!verified_methods_lock_);
+ const VerifiedMethod* GetVerifiedMethod(MethodReference ref)
+ REQUIRES(!verified_methods_lock_);
- void AddRejectedClass(ClassReference ref) REQUIRES(!rejected_classes_lock_);
- bool IsClassRejected(ClassReference ref) REQUIRES(!rejected_classes_lock_);
+ void AddRejectedClass(ClassReference ref) REQUIRES(!rejected_classes_lock_);
+ bool IsClassRejected(ClassReference ref) REQUIRES(!rejected_classes_lock_);
- bool IsCandidateForCompilation(MethodReference& method_ref,
- const uint32_t access_flags);
+ bool IsCandidateForCompilation(MethodReference& method_ref, const uint32_t access_flags);
- private:
- const CompilerOptions* const compiler_options_;
+ // Add a dex file array to the preregistered_dex_files_ array. These dex files require no locks to
+ // access. It is not safe to call if other callers are calling GetVerifiedMethod concurrently.
+ void PreRegisterDexFile(const DexFile* dex_file) REQUIRES(!verified_methods_lock_);
- // Verified methods.
- typedef SafeMap<MethodReference, const VerifiedMethod*,
- MethodReferenceComparator> VerifiedMethodMap;
- ReaderWriterMutex verified_methods_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
- VerifiedMethodMap verified_methods_ GUARDED_BY(verified_methods_lock_);
+ private:
+ // Verified methods. The method array is fixed to avoid needing a lock to extend it.
+ using DexFileMethodArray = dchecked_vector<Atomic<const VerifiedMethod*>>;
+ using DexFileResults = std::map<const DexFile*, DexFileMethodArray>;
+ using VerifiedMethodMap = SafeMap<MethodReference,
+ const VerifiedMethod*,
+ MethodReferenceComparator>;
- // Rejected classes.
- ReaderWriterMutex rejected_classes_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
- std::set<ClassReference> rejected_classes_ GUARDED_BY(rejected_classes_lock_);
+ static void DeleteResults(DexFileResults& array);
+
+ DexFileMethodArray* GetMethodArray(const DexFile* dex_file) REQUIRES(!verified_methods_lock_);
+ VerifiedMethodMap verified_methods_ GUARDED_BY(verified_methods_lock_);
+ const CompilerOptions* const compiler_options_;
+
+ // Dex2oat can preregister dex files to avoid locking when calling GetVerifiedMethod.
+ DexFileResults preregistered_dex_files_;
+
+ ReaderWriterMutex verified_methods_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
+
+ // Rejected classes.
+ ReaderWriterMutex rejected_classes_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
+ std::set<ClassReference> rejected_classes_ GUARDED_BY(rejected_classes_lock_);
};
} // namespace art
diff --git a/compiler/dex/verified_method.cc b/compiler/dex/verified_method.cc
index e19fb7b..1bdace9 100644
--- a/compiler/dex/verified_method.cc
+++ b/compiler/dex/verified_method.cc
@@ -230,7 +230,7 @@
const verifier::RegType& reg_type(line->GetRegisterType(method_verifier,
inst->VRegA_21c()));
const verifier::RegType& cast_type =
- method_verifier->ResolveCheckedClass(inst->VRegB_21c());
+ method_verifier->ResolveCheckedClass(dex::TypeIndex(inst->VRegB_21c()));
is_safe_cast = cast_type.IsStrictlyAssignableFrom(reg_type, method_verifier);
} else {
const verifier::RegType& array_type(line->GetRegisterType(method_verifier,
diff --git a/compiler/driver/compiler_driver-inl.h b/compiler/driver/compiler_driver-inl.h
index 9711516..f056dd3 100644
--- a/compiler/driver/compiler_driver-inl.h
+++ b/compiler/driver/compiler_driver-inl.h
@@ -38,7 +38,7 @@
inline mirror::Class* CompilerDriver::ResolveClass(
const ScopedObjectAccess& soa, Handle<mirror::DexCache> dex_cache,
- Handle<mirror::ClassLoader> class_loader, uint16_t cls_index,
+ Handle<mirror::ClassLoader> class_loader, dex::TypeIndex cls_index,
const DexCompilationUnit* mUnit) {
DCHECK_EQ(dex_cache->GetDexFile(), mUnit->GetDexFile());
DCHECK_EQ(class_loader.Get(), GetClassLoader(soa, mUnit));
@@ -141,7 +141,7 @@
mirror::Class* referrer_class,
ArtMember* resolved_member,
uint16_t member_idx,
- uint32_t* storage_index) {
+ dex::TypeIndex* storage_index) {
DCHECK(resolved_member->IsStatic());
if (LIKELY(referrer_class != nullptr)) {
ObjPtr<mirror::Class> members_class = resolved_member->GetDeclaringClass();
@@ -156,7 +156,7 @@
// TODO: for images we can elide the static storage base null check
// if we know there's a non-null entry in the image
const DexFile* dex_file = dex_cache->GetDexFile();
- uint32_t storage_idx = DexFile::kDexNoIndex;
+ dex::TypeIndex storage_idx(DexFile::kDexNoIndex16);
if (LIKELY(members_class->GetDexCache() == dex_cache)) {
// common case where the dex cache of both the referrer and the member are the same,
// no need to search the dex file
@@ -166,27 +166,27 @@
// of the class mentioned in the dex file and there is no dex cache entry.
storage_idx = resolved_member->GetDeclaringClass()->FindTypeIndexInOtherDexFile(*dex_file);
}
- if (storage_idx != DexFile::kDexNoIndex) {
+ if (storage_idx.IsValid()) {
*storage_index = storage_idx;
return std::make_pair(true, !resolved_member->IsFinal());
}
}
}
// Conservative defaults.
- *storage_index = DexFile::kDexNoIndex;
+ *storage_index = dex::TypeIndex(DexFile::kDexNoIndex16);
return std::make_pair(false, false);
}
inline std::pair<bool, bool> CompilerDriver::IsFastStaticField(
mirror::DexCache* dex_cache, mirror::Class* referrer_class,
- ArtField* resolved_field, uint16_t field_idx, uint32_t* storage_index) {
+ ArtField* resolved_field, uint16_t field_idx, dex::TypeIndex* storage_index) {
return IsClassOfStaticMemberAvailableToReferrer(
dex_cache, referrer_class, resolved_field, field_idx, storage_index);
}
inline bool CompilerDriver::IsClassOfStaticMethodAvailableToReferrer(
mirror::DexCache* dex_cache, mirror::Class* referrer_class,
- ArtMethod* resolved_method, uint16_t method_idx, uint32_t* storage_index) {
+ ArtMethod* resolved_method, uint16_t method_idx, dex::TypeIndex* storage_index) {
std::pair<bool, bool> result = IsClassOfStaticMemberAvailableToReferrer(
dex_cache, referrer_class, resolved_method, method_idx, storage_index);
// Only the first member of `result` is meaningful, as there is no
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index 223be88..ad75ec4 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -45,6 +45,7 @@
#include "dex_file-inl.h"
#include "dex_instruction-inl.h"
#include "dex/dex_to_dex_compiler.h"
+#include "dex/dex_to_dex_decompiler.h"
#include "dex/verification_results.h"
#include "dex/verified_method.h"
#include "driver/compiler_options.h"
@@ -72,6 +73,7 @@
#include "transaction.h"
#include "utils/dex_cache_arrays_layout-inl.h"
#include "utils/swap_space.h"
+#include "vdex_file.h"
#include "verifier/method_verifier.h"
#include "verifier/method_verifier-inl.h"
#include "verifier/verifier_log_mode.h"
@@ -394,7 +396,6 @@
void CompilerDriver::CompileAll(jobject class_loader,
const std::vector<const DexFile*>& dex_files,
- verifier::VerifierDeps* verifier_deps,
TimingLogger* timings) {
DCHECK(!Runtime::Current()->IsStarted());
@@ -406,7 +407,7 @@
// 2) Resolve all classes
// 3) Attempt to verify all classes
// 4) Attempt to initialize image classes, and trivially initialized classes
- PreCompile(class_loader, dex_files, verifier_deps, timings);
+ PreCompile(class_loader, dex_files, timings);
if (GetCompilerOptions().IsBootImage()) {
// We don't need to setup the intrinsics for non boot image compilation, as
// those compilations will pick up a boot image that have the ArtMethod already
@@ -433,6 +434,72 @@
FreeThreadPools();
}
+// In-place unquicken the given `dex_files` based on `quickening_info`.
+static void Unquicken(const std::vector<const DexFile*>& dex_files,
+ const ArrayRef<const uint8_t>& quickening_info) {
+ const uint8_t* quickening_info_ptr = quickening_info.data();
+ const uint8_t* const quickening_info_end = quickening_info.data() + quickening_info.size();
+ for (const DexFile* dex_file : dex_files) {
+ for (uint32_t i = 0; i < dex_file->NumClassDefs(); ++i) {
+ const DexFile::ClassDef& class_def = dex_file->GetClassDef(i);
+ const uint8_t* class_data = dex_file->GetClassData(class_def);
+ if (class_data == nullptr) {
+ continue;
+ }
+ ClassDataItemIterator it(*dex_file, class_data);
+ // Skip fields
+ while (it.HasNextStaticField()) {
+ it.Next();
+ }
+ while (it.HasNextInstanceField()) {
+ it.Next();
+ }
+
+ // Unquicken each method.
+ while (it.HasNextDirectMethod()) {
+ const DexFile::CodeItem* code_item = it.GetMethodCodeItem();
+ if (code_item != nullptr) {
+ uint32_t quickening_size = *reinterpret_cast<const uint32_t*>(quickening_info_ptr);
+ quickening_info_ptr += sizeof(uint32_t);
+ optimizer::ArtDecompileDEX(
+ *code_item, ArrayRef<const uint8_t>(quickening_info_ptr, quickening_size));
+ quickening_info_ptr += quickening_size;
+ }
+ it.Next();
+ }
+
+ while (it.HasNextVirtualMethod()) {
+ const DexFile::CodeItem* code_item = it.GetMethodCodeItem();
+ if (code_item != nullptr) {
+ uint32_t quickening_size = *reinterpret_cast<const uint32_t*>(quickening_info_ptr);
+ quickening_info_ptr += sizeof(uint32_t);
+ optimizer::ArtDecompileDEX(
+ *code_item, ArrayRef<const uint8_t>(quickening_info_ptr, quickening_size));
+ quickening_info_ptr += quickening_size;
+ }
+ it.Next();
+ }
+ DCHECK(!it.HasNext());
+ }
+ }
+ DCHECK_EQ(quickening_info_ptr, quickening_info_end) << "Failed to use all quickening info";
+}
+
+void CompilerDriver::CompileAll(jobject class_loader,
+ const std::vector<const DexFile*>& dex_files,
+ VdexFile* vdex_file,
+ TimingLogger* timings) {
+ if (vdex_file != nullptr) {
+ // TODO: we unquicken unconditionnally, as we don't know
+ // if the boot image has changed. How exactly we'll know is under
+ // experimentation.
+ Unquicken(dex_files, vdex_file->GetQuickeningInfo());
+ Runtime::Current()->GetCompilerCallbacks()->SetVerifierDeps(
+ new verifier::VerifierDeps(dex_files, vdex_file->GetVerifierDepsData()));
+ }
+ CompileAll(class_loader, dex_files, timings);
+}
+
static optimizer::DexToDexCompilationLevel GetDexToDexCompilationLevel(
Thread* self, const CompilerDriver& driver, Handle<mirror::ClassLoader> class_loader,
const DexFile& dex_file, const DexFile::ClassDef& class_def)
@@ -538,14 +605,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)
@@ -678,7 +740,7 @@
InitializeThreadPools();
- PreCompile(jclass_loader, dex_files, /* verifier_deps */ nullptr, timings);
+ PreCompile(jclass_loader, dex_files, timings);
// Can we run DEX-to-DEX compiler on this class ?
optimizer::DexToDexCompilationLevel dex_to_dex_compilation_level =
@@ -875,7 +937,6 @@
void CompilerDriver::PreCompile(jobject class_loader,
const std::vector<const DexFile*>& dex_files,
- verifier::VerifierDeps* verifier_deps,
TimingLogger* timings) {
CheckThreadPools();
@@ -909,7 +970,7 @@
VLOG(compiler) << "Resolve const-strings: " << GetMemoryUsageString(false);
}
- Verify(class_loader, dex_files, verifier_deps, timings);
+ Verify(class_loader, dex_files, timings);
VLOG(compiler) << "Verify: " << GetMemoryUsageString(false);
if (had_hard_verifier_failure_ && GetCompilerOptions().AbortOnHardVerifierFailure()) {
@@ -973,11 +1034,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);
+ dex::TypeIndex 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;
}
@@ -985,7 +1047,7 @@
class ResolveCatchBlockExceptionsClassVisitor : public ClassVisitor {
public:
explicit ResolveCatchBlockExceptionsClassVisitor(
- std::set<std::pair<uint16_t, const DexFile*>>& exceptions_to_resolve)
+ std::set<std::pair<dex::TypeIndex, const DexFile*>>& exceptions_to_resolve)
: exceptions_to_resolve_(exceptions_to_resolve) {}
virtual bool operator()(ObjPtr<mirror::Class> c) OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_) {
@@ -1016,8 +1078,8 @@
has_catch_all = true;
}
for (int32_t j = 0; j < encoded_catch_handler_size; j++) {
- uint16_t encoded_catch_handler_handlers_type_idx =
- DecodeUnsignedLeb128(&encoded_catch_handler_list);
+ dex::TypeIndex encoded_catch_handler_handlers_type_idx =
+ dex::TypeIndex(DecodeUnsignedLeb128(&encoded_catch_handler_list));
// Add to set of types to resolve if not already in the dex cache resolved types
if (!method_handle->IsResolvedTypeIdx(encoded_catch_handler_handlers_type_idx,
pointer_size)) {
@@ -1034,7 +1096,7 @@
}
}
- std::set<std::pair<uint16_t, const DexFile*>>& exceptions_to_resolve_;
+ std::set<std::pair<dex::TypeIndex, const DexFile*>>& exceptions_to_resolve_;
};
class RecordImageClassesVisitor : public ClassVisitor {
@@ -1082,7 +1144,7 @@
// Resolve exception classes referenced by the loaded classes. The catch logic assumes
// exceptions are resolved by the verifier when there is a catch block in an interested method.
// Do this here so that exception classes appear to have been specified image classes.
- std::set<std::pair<uint16_t, const DexFile*>> unresolved_exception_types;
+ std::set<std::pair<dex::TypeIndex, const DexFile*>> unresolved_exception_types;
StackHandleScope<1> hs(self);
Handle<mirror::Class> java_lang_Throwable(
hs.NewHandle(class_linker->FindSystemClass(self, "Ljava/lang/Throwable;")));
@@ -1090,8 +1152,8 @@
unresolved_exception_types.clear();
ResolveCatchBlockExceptionsClassVisitor visitor(unresolved_exception_types);
class_linker->VisitClasses(&visitor);
- for (const std::pair<uint16_t, const DexFile*>& exception_type : unresolved_exception_types) {
- uint16_t exception_type_idx = exception_type.first;
+ for (const auto& exception_type : unresolved_exception_types) {
+ dex::TypeIndex exception_type_idx = exception_type.first;
const DexFile* dex_file = exception_type.second;
StackHandleScope<2> hs2(self);
Handle<mirror::DexCache> dex_cache(hs2.NewHandle(class_linker->RegisterDexFile(*dex_file,
@@ -1342,7 +1404,7 @@
bool CompilerDriver::CanAccessTypeWithoutChecks(uint32_t referrer_idx,
Handle<mirror::DexCache> dex_cache,
- uint32_t type_idx) {
+ dex::TypeIndex type_idx) {
// Get type from dex cache assuming it was populated by the verifier
mirror::Class* resolved_class = dex_cache->GetResolvedType(type_idx);
if (resolved_class == nullptr) {
@@ -1371,7 +1433,7 @@
bool CompilerDriver::CanAccessInstantiableTypeWithoutChecks(uint32_t referrer_idx,
Handle<mirror::DexCache> dex_cache,
- uint32_t type_idx,
+ dex::TypeIndex type_idx,
bool* finalizable) {
// Get type from dex cache assuming it was populated by the verifier.
mirror::Class* resolved_class = dex_cache->GetResolvedType(type_idx);
@@ -1865,7 +1927,7 @@
public:
explicit ResolveTypeVisitor(const ParallelCompilationManager* manager) : manager_(manager) {
}
- virtual void Visit(size_t type_idx) OVERRIDE REQUIRES(!Locks::mutator_lock_) {
+ void Visit(size_t type_idx) OVERRIDE REQUIRES(!Locks::mutator_lock_) {
// Class derived values are more complicated, they require the linker and loader.
ScopedObjectAccess soa(Thread::Current());
ClassLinker* class_linker = manager_->GetClassLinker();
@@ -1876,7 +1938,10 @@
Handle<mirror::DexCache> dex_cache(hs.NewHandle(class_linker->RegisterDexFile(
dex_file,
class_loader.Get())));
- mirror::Class* klass = class_linker->ResolveType(dex_file, type_idx, dex_cache, class_loader);
+ mirror::Class* klass = class_linker->ResolveType(dex_file,
+ dex::TypeIndex(type_idx),
+ dex_cache,
+ class_loader);
if (klass == nullptr) {
soa.Self()->AssertPendingException();
@@ -1937,8 +2002,10 @@
void CompilerDriver::Verify(jobject jclass_loader,
const std::vector<const DexFile*>& dex_files,
- verifier::VerifierDeps* verifier_deps,
TimingLogger* timings) {
+ verifier::VerifierDeps* verifier_deps =
+ Runtime::Current()->GetCompilerCallbacks()->GetVerifierDeps();
+ // If there is an existing `VerifierDeps`, try to use it for fast verification.
if (verifier_deps != nullptr) {
TimingLogger::ScopedTiming t("Fast Verify", timings);
ScopedObjectAccess soa(Thread::Current());
@@ -1956,9 +2023,9 @@
for (const DexFile* dex_file : dex_files) {
// Fetch the list of unverified classes and turn it into a set for faster
// lookups.
- const std::vector<uint16_t>& unverified_classes =
+ const std::vector<dex::TypeIndex>& unverified_classes =
verifier_deps->GetUnverifiedClasses(*dex_file);
- std::set<uint16_t> set(unverified_classes.begin(), unverified_classes.end());
+ std::set<dex::TypeIndex> set(unverified_classes.begin(), unverified_classes.end());
for (uint32_t i = 0; i < dex_file->NumClassDefs(); ++i) {
const DexFile::ClassDef& class_def = dex_file->GetClassDef(i);
const char* descriptor = dex_file->GetClassDescriptor(class_def);
@@ -1976,13 +2043,20 @@
}
}
- // If there is no passed `verifier_deps` (because of non-existing vdex), or
- // the passed `verifier_deps` is not valid anymore, create a new one for
+ // If there is no existing `verifier_deps` (because of non-existing vdex), or
+ // the existing `verifier_deps` is not valid anymore, create a new one for
// non boot image compilation. The verifier will need it to record the new dependencies.
// Then dex2oat can update the vdex file with these new dependencies.
if (!GetCompilerOptions().IsBootImage()) {
- Runtime::Current()->GetCompilerCallbacks()->SetVerifierDeps(
- new verifier::VerifierDeps(dex_files));
+ // Create the main VerifierDeps, and set it to this thread.
+ verifier_deps = new verifier::VerifierDeps(dex_files);
+ Runtime::Current()->GetCompilerCallbacks()->SetVerifierDeps(verifier_deps);
+ Thread::Current()->SetVerifierDeps(verifier_deps);
+ // Create per-thread VerifierDeps to avoid contention on the main one.
+ // We will merge them after verification.
+ for (ThreadPoolWorker* worker : parallel_thread_pool_->GetWorkers()) {
+ worker->GetThread()->SetVerifierDeps(new verifier::VerifierDeps(dex_files));
+ }
}
// Note: verification should not be pulling in classes anymore when compiling the boot image,
// as all should have been resolved before. As such, doing this in parallel should still
@@ -1996,6 +2070,17 @@
parallel_thread_count_,
timings);
}
+
+ if (!GetCompilerOptions().IsBootImage()) {
+ // Merge all VerifierDeps into the main one.
+ for (ThreadPoolWorker* worker : parallel_thread_pool_->GetWorkers()) {
+ verifier::VerifierDeps* thread_deps = worker->GetThread()->GetVerifierDeps();
+ worker->GetThread()->SetVerifierDeps(nullptr);
+ verifier_deps->MergeWith(*thread_deps, dex_files);;
+ delete thread_deps;
+ }
+ Thread::Current()->SetVerifierDeps(nullptr);
+ }
}
class VerifyClassVisitor : public CompilationVisitor {
diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h
index c8d6cb0..7418b00 100644
--- a/compiler/driver/compiler_driver.h
+++ b/compiler/driver/compiler_driver.h
@@ -31,6 +31,7 @@
#include "class_reference.h"
#include "compiler.h"
#include "dex_file.h"
+#include "dex_file_types.h"
#include "driver/compiled_method_storage.h"
#include "jit/offline_profiling_info.h"
#include "invoke_type.h"
@@ -50,7 +51,6 @@
namespace verifier {
class MethodVerifier;
-class VerifierDeps;
class VerifierDepsTest;
} // namespace verifier
@@ -68,6 +68,7 @@
using SwapSrcMap = SrcMap<SwapAllocator<SrcMapElem>>;
template<class T> class Handle;
class TimingLogger;
+class VdexFile;
class VerificationResults;
class VerifiedMethod;
@@ -118,7 +119,12 @@
void CompileAll(jobject class_loader,
const std::vector<const DexFile*>& dex_files,
- verifier::VerifierDeps* verifier_deps,
+ TimingLogger* timings)
+ REQUIRES(!Locks::mutator_lock_, !compiled_classes_lock_, !dex_to_dex_references_lock_);
+
+ void CompileAll(jobject class_loader,
+ const std::vector<const DexFile*>& dex_files,
+ VdexFile* vdex_file,
TimingLogger* timings)
REQUIRES(!Locks::mutator_lock_, !compiled_classes_lock_, !dex_to_dex_references_lock_);
@@ -188,14 +194,14 @@
// Are runtime access checks necessary in the compiled code?
bool CanAccessTypeWithoutChecks(uint32_t referrer_idx,
Handle<mirror::DexCache> dex_cache,
- uint32_t type_idx)
+ dex::TypeIndex type_idx)
REQUIRES_SHARED(Locks::mutator_lock_);
// Are runtime access and instantiable checks necessary in the code?
// out_is_finalizable is set to whether the type is finalizable.
bool CanAccessInstantiableTypeWithoutChecks(uint32_t referrer_idx,
Handle<mirror::DexCache> dex_cache,
- uint32_t type_idx,
+ dex::TypeIndex type_idx,
bool* out_is_finalizable)
REQUIRES_SHARED(Locks::mutator_lock_);
@@ -207,7 +213,7 @@
mirror::Class* ResolveClass(
const ScopedObjectAccess& soa, Handle<mirror::DexCache> dex_cache,
- Handle<mirror::ClassLoader> class_loader, uint16_t type_index,
+ Handle<mirror::ClassLoader> class_loader, dex::TypeIndex type_index,
const DexCompilationUnit* mUnit)
REQUIRES_SHARED(Locks::mutator_lock_);
@@ -234,9 +240,11 @@
// Can we fast-path an SGET/SPUT access to a static field? If yes, compute the type index
// of the declaring class in the referrer's dex file.
- std::pair<bool, bool> IsFastStaticField(
- mirror::DexCache* dex_cache, mirror::Class* referrer_class,
- ArtField* resolved_field, uint16_t field_idx, uint32_t* storage_index)
+ std::pair<bool, bool> IsFastStaticField(mirror::DexCache* dex_cache,
+ mirror::Class* referrer_class,
+ ArtField* resolved_field,
+ uint16_t field_idx,
+ dex::TypeIndex* storage_index)
REQUIRES_SHARED(Locks::mutator_lock_);
// Return whether the declaring class of `resolved_method` is
@@ -248,7 +256,7 @@
mirror::Class* referrer_class,
ArtMethod* resolved_method,
uint16_t method_idx,
- uint32_t* storage_index)
+ dex::TypeIndex* storage_index)
REQUIRES_SHARED(Locks::mutator_lock_);
// Resolve a method. Returns null on failure, including incompatible class change.
@@ -395,7 +403,7 @@
mirror::Class* referrer_class,
ArtMember* resolved_member,
uint16_t member_idx,
- uint32_t* storage_index)
+ dex::TypeIndex* storage_index)
REQUIRES_SHARED(Locks::mutator_lock_);
// Can `referrer_class` access the resolved `member`?
@@ -417,7 +425,6 @@
private:
void PreCompile(jobject class_loader,
const std::vector<const DexFile*>& dex_files,
- verifier::VerifierDeps* verifier_deps,
TimingLogger* timings)
REQUIRES(!Locks::mutator_lock_, !compiled_classes_lock_);
@@ -440,7 +447,6 @@
void Verify(jobject class_loader,
const std::vector<const DexFile*>& dex_files,
- verifier::VerifierDeps* verifier_deps,
TimingLogger* timings);
void VerifyDexFile(jobject class_loader,
@@ -584,6 +590,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_driver_test.cc b/compiler/driver/compiler_driver_test.cc
index 9679a79..f40c712 100644
--- a/compiler/driver/compiler_driver_test.cc
+++ b/compiler/driver/compiler_driver_test.cc
@@ -24,6 +24,7 @@
#include "class_linker-inl.h"
#include "common_compiler_test.h"
#include "dex_file.h"
+#include "dex_file_types.h"
#include "gc/heap.h"
#include "mirror/class-inl.h"
#include "mirror/class_loader.h"
@@ -115,9 +116,9 @@
}
EXPECT_EQ(dex.NumTypeIds(), dex_cache->NumResolvedTypes());
for (size_t i = 0; i < dex_cache->NumResolvedTypes(); i++) {
- mirror::Class* type = dex_cache->GetResolvedType(i);
+ mirror::Class* type = dex_cache->GetResolvedType(dex::TypeIndex(i));
EXPECT_TRUE(type != nullptr) << "type_idx=" << i
- << " " << dex.GetTypeDescriptor(dex.GetTypeId(i));
+ << " " << dex.GetTypeDescriptor(dex.GetTypeId(dex::TypeIndex(i)));
}
EXPECT_EQ(dex.NumMethodIds(), dex_cache->NumResolvedMethods());
auto* cl = Runtime::Current()->GetClassLinker();
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_test.cc b/compiler/image_test.cc
index fcb8979..5629dff 100644
--- a/compiler/image_test.cc
+++ b/compiler/image_test.cc
@@ -211,7 +211,9 @@
&driver->GetCompilerOptions(),
oat_file.GetFile()));
elf_writers.back()->Start();
- oat_writers.emplace_back(new OatWriter(/*compiling_boot_image*/true, &timings));
+ oat_writers.emplace_back(new OatWriter(/*compiling_boot_image*/true,
+ &timings,
+ /*profile_compilation_info*/nullptr));
}
std::vector<OutputStream*> rodata;
diff --git a/compiler/image_writer.cc b/compiler/image_writer.cc
index 51ef440..a706697 100644
--- a/compiler/image_writer.cc
+++ b/compiler/image_writer.cc
@@ -32,6 +32,7 @@
#include "class_linker-inl.h"
#include "compiled_method.h"
#include "dex_file-inl.h"
+#include "dex_file_types.h"
#include "driver/compiler_driver.h"
#include "elf_file.h"
#include "elf_utils.h"
@@ -697,7 +698,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 +838,7 @@
return true;
}
-class NonImageClassesVisitor : public ClassVisitor {
+class ImageWriter::NonImageClassesVisitor : public ClassVisitor {
public:
explicit NonImageClassesVisitor(ImageWriter* image_writer) : image_writer_(image_writer) {}
@@ -890,9 +891,9 @@
}
ObjPtr<mirror::DexCache> dex_cache = self->DecodeJObject(data.weak_root)->AsDexCache();
for (size_t i = 0; i < dex_cache->NumResolvedTypes(); i++) {
- Class* klass = dex_cache->GetResolvedType(i);
+ Class* klass = dex_cache->GetResolvedType(dex::TypeIndex(i));
if (klass != nullptr && !KeepClass(klass)) {
- dex_cache->SetResolvedType(i, nullptr);
+ dex_cache->SetResolvedType(dex::TypeIndex(i), nullptr);
}
}
ArtMethod** resolved_methods = dex_cache->GetResolvedMethods();
@@ -1701,7 +1702,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 +1945,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 +1981,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 +2046,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/oat_test.cc b/compiler/oat_test.cc
index 102637f..9458576 100644
--- a/compiler/oat_test.cc
+++ b/compiler/oat_test.cc
@@ -125,7 +125,9 @@
SafeMap<std::string, std::string>& key_value_store,
bool verify) {
TimingLogger timings("WriteElf", false, false);
- OatWriter oat_writer(/*compiling_boot_image*/false, &timings);
+ OatWriter oat_writer(/*compiling_boot_image*/false,
+ &timings,
+ /*profile_compilation_info*/nullptr);
for (const DexFile* dex_file : dex_files) {
ArrayRef<const uint8_t> raw_dex_file(
reinterpret_cast<const uint8_t*>(&dex_file->GetHeader()),
@@ -145,7 +147,9 @@
SafeMap<std::string, std::string>& key_value_store,
bool verify) {
TimingLogger timings("WriteElf", false, false);
- OatWriter oat_writer(/*compiling_boot_image*/false, &timings);
+ OatWriter oat_writer(/*compiling_boot_image*/false,
+ &timings,
+ /*profile_compilation_info*/nullptr);
for (const char* dex_filename : dex_filenames) {
if (!oat_writer.AddDexFileSource(dex_filename, dex_filename)) {
return false;
@@ -161,7 +165,9 @@
SafeMap<std::string, std::string>& key_value_store,
bool verify) {
TimingLogger timings("WriteElf", false, false);
- OatWriter oat_writer(/*compiling_boot_image*/false, &timings);
+ OatWriter oat_writer(/*compiling_boot_image*/false,
+ &timings,
+ /*profile_compilation_info*/nullptr);
if (!oat_writer.AddZippedDexFilesSource(std::move(zip_fd), location)) {
return false;
}
diff --git a/compiler/oat_writer.cc b/compiler/oat_writer.cc
index f9173f5..153aff4 100644
--- a/compiler/oat_writer.cc
+++ b/compiler/oat_writer.cc
@@ -33,6 +33,7 @@
#include "debug/method_debug_info.h"
#include "dex/verification_results.h"
#include "dex_file-inl.h"
+#include "dexlayout.h"
#include "driver/compiler_driver.h"
#include "driver/compiler_options.h"
#include "gc/space/image_space.h"
@@ -260,16 +261,7 @@
// Data to write to a separate section.
dchecked_vector<uint32_t> class_offsets_;
- void InitTypeLookupTable(const DexFile& dex_file, uint8_t* storage) const {
- lookup_table_.reset(TypeLookupTable::Create(dex_file, storage));
- }
-
- TypeLookupTable* GetTypeLookupTable() const {
- return lookup_table_.get();
- }
-
private:
- mutable std::unique_ptr<TypeLookupTable> lookup_table_;
size_t GetClassOffsetsRawSize() const {
return class_offsets_.size() * sizeof(class_offsets_[0]);
}
@@ -285,7 +277,7 @@
DCHECK_EQ(static_cast<off_t>(file_offset + offset_), out->Seek(0, kSeekCurrent)) \
<< "file_offset=" << file_offset << " offset_=" << offset_
-OatWriter::OatWriter(bool compiling_boot_image, TimingLogger* timings)
+OatWriter::OatWriter(bool compiling_boot_image, TimingLogger* timings, ProfileCompilationInfo* info)
: write_state_(WriteState::kAddingDexFileSources),
timings_(timings),
raw_dex_files_(),
@@ -346,7 +338,8 @@
size_oat_class_method_bitmaps_(0),
size_oat_class_method_offsets_(0),
relative_patcher_(nullptr),
- absolute_patch_locations_() {
+ absolute_patch_locations_(),
+ profile_compilation_info_(info) {
}
bool OatWriter::AddDexFileSource(const char* filename,
@@ -410,6 +403,35 @@
return true;
}
+// Add dex file source(s) from a vdex file specified by a file handle.
+bool OatWriter::AddVdexDexFilesSource(const VdexFile& vdex_file,
+ const char* location,
+ CreateTypeLookupTable create_type_lookup_table) {
+ DCHECK(write_state_ == WriteState::kAddingDexFileSources);
+ const uint8_t* current_dex_data = nullptr;
+ for (size_t i = 0; ; ++i) {
+ current_dex_data = vdex_file.GetNextDexFileData(current_dex_data);
+ if (current_dex_data == nullptr) {
+ break;
+ }
+ if (!DexFile::IsMagicValid(current_dex_data)) {
+ LOG(ERROR) << "Invalid magic in vdex file created from " << location;
+ return false;
+ }
+ // We used `zipped_dex_file_locations_` to keep the strings in memory.
+ zipped_dex_file_locations_.push_back(DexFile::GetMultiDexLocation(i, location));
+ const char* full_location = zipped_dex_file_locations_.back().c_str();
+ oat_dex_files_.emplace_back(full_location,
+ DexFileSource(current_dex_data),
+ create_type_lookup_table);
+ }
+ if (oat_dex_files_.empty()) {
+ LOG(ERROR) << "No dex files in vdex file created from " << location;
+ return false;
+ }
+ return true;
+}
+
// Add dex file source from raw memory.
bool OatWriter::AddRawDexFileSource(const ArrayRef<const uint8_t>& data,
const char* location,
@@ -2090,7 +2112,11 @@
if (!SeekToDexFile(out, file, oat_dex_file)) {
return false;
}
- if (oat_dex_file->source_.IsZipEntry()) {
+ if (profile_compilation_info_ != nullptr) {
+ if (!LayoutAndWriteDexFile(out, oat_dex_file)) {
+ return false;
+ }
+ } else if (oat_dex_file->source_.IsZipEntry()) {
if (!WriteDexFile(out, file, oat_dex_file, oat_dex_file->source_.GetZipEntry())) {
return false;
}
@@ -2155,6 +2181,39 @@
return true;
}
+bool OatWriter::LayoutAndWriteDexFile(OutputStream* out, OatDexFile* oat_dex_file) {
+ TimingLogger::ScopedTiming split("Dex Layout", timings_);
+ std::string error_msg;
+ std::string location(oat_dex_file->GetLocation());
+ std::unique_ptr<const DexFile> dex_file;
+ if (oat_dex_file->source_.IsZipEntry()) {
+ ZipEntry* zip_entry = oat_dex_file->source_.GetZipEntry();
+ std::unique_ptr<MemMap> mem_map(
+ zip_entry->ExtractToMemMap(location.c_str(), "classes.dex", &error_msg));
+ dex_file = DexFile::Open(location,
+ zip_entry->GetCrc32(),
+ std::move(mem_map),
+ /* verify */ true,
+ /* verify_checksum */ true,
+ &error_msg);
+ } else {
+ DCHECK(oat_dex_file->source_.IsRawFile());
+ File* raw_file = oat_dex_file->source_.GetRawFile();
+ dex_file = DexFile::OpenDex(raw_file->Fd(), location, /* verify_checksum */ true, &error_msg);
+ }
+ Options options;
+ options.output_to_memmap_ = true;
+ DexLayout dex_layout(options, profile_compilation_info_, nullptr);
+ dex_layout.ProcessDexFile(location.c_str(), dex_file.get(), 0);
+ std::unique_ptr<MemMap> mem_map(dex_layout.GetAndReleaseMemMap());
+ if (!WriteDexFile(out, oat_dex_file, mem_map->Begin())) {
+ return false;
+ }
+ // Set the checksum of the new oat dex file to be the original file's checksum.
+ oat_dex_file->dex_file_location_checksum_ = dex_file->GetLocationChecksum();
+ return true;
+}
+
bool OatWriter::WriteDexFile(OutputStream* out,
File* file,
OatDexFile* oat_dex_file,
@@ -2481,8 +2540,15 @@
// Create the lookup table. When `nullptr` is given as the storage buffer,
// TypeLookupTable allocates its own and OatDexFile takes ownership.
- oat_dex_file->InitTypeLookupTable(*opened_dex_files[i], /* storage */ nullptr);
- TypeLookupTable* table = oat_dex_file->GetTypeLookupTable();
+ const DexFile& dex_file = *opened_dex_files[i];
+ {
+ std::unique_ptr<TypeLookupTable> type_lookup_table =
+ TypeLookupTable::Create(dex_file, /* storage */ nullptr);
+ type_lookup_table_oat_dex_files_.push_back(
+ std::make_unique<art::OatDexFile>(std::move(type_lookup_table)));
+ dex_file.SetOatDexFile(type_lookup_table_oat_dex_files_.back().get());
+ }
+ TypeLookupTable* const table = type_lookup_table_oat_dex_files_.back()->GetTypeLookupTable();
// Type tables are required to be 4 byte aligned.
size_t initial_offset = oat_size_;
diff --git a/compiler/oat_writer.h b/compiler/oat_writer.h
index 3d08ad3..0dcf79e 100644
--- a/compiler/oat_writer.h
+++ b/compiler/oat_writer.h
@@ -38,9 +38,11 @@
class CompiledMethod;
class CompilerDriver;
class ImageWriter;
+class ProfileCompilationInfo;
class OutputStream;
class TimingLogger;
class TypeLookupTable;
+class VdexFile;
class ZipEntry;
namespace debug {
@@ -110,12 +112,13 @@
kDefault = kCreate
};
- OatWriter(bool compiling_boot_image, TimingLogger* timings);
+ OatWriter(bool compiling_boot_image, TimingLogger* timings, ProfileCompilationInfo* info);
// To produce a valid oat file, the user must first add sources with any combination of
// - AddDexFileSource(),
// - AddZippedDexFilesSource(),
- // - AddRawDexFileSource().
+ // - AddRawDexFileSource(),
+ // - AddVdexDexFilesSource().
// Then the user must call in order
// - WriteAndOpenDexFiles()
// - Initialize()
@@ -144,6 +147,11 @@
const char* location,
uint32_t location_checksum,
CreateTypeLookupTable create_type_lookup_table = CreateTypeLookupTable::kDefault);
+ // Add dex file source(s) from a vdex file.
+ bool AddVdexDexFilesSource(
+ const VdexFile& vdex_file,
+ const char* location,
+ CreateTypeLookupTable create_type_lookup_table = CreateTypeLookupTable::kDefault);
dchecked_vector<const char*> GetSourceLocations() const;
// Write raw dex files to the vdex file, mmap the file and open the dex files from it.
@@ -258,6 +266,7 @@
bool WriteDexFiles(OutputStream* out, File* file);
bool WriteDexFile(OutputStream* out, File* file, OatDexFile* oat_dex_file);
bool SeekToDexFile(OutputStream* out, File* file, OatDexFile* oat_dex_file);
+ bool LayoutAndWriteDexFile(OutputStream* out, OatDexFile* oat_dex_file);
bool WriteDexFile(OutputStream* out,
File* file,
OatDexFile* oat_dex_file,
@@ -363,6 +372,9 @@
// Offset of the oat data from the start of the mmapped region of the elf file.
size_t oat_data_offset_;
+ // Fake OatDexFiles to hold type lookup tables for the compiler.
+ std::vector<std::unique_ptr<art::OatDexFile>> type_lookup_table_oat_dex_files_;
+
// data to write
std::unique_ptr<OatHeader> oat_header_;
dchecked_vector<OatDexFile> oat_dex_files_;
@@ -419,6 +431,9 @@
// The locations of absolute patches relative to the start of the executable section.
dchecked_vector<uintptr_t> absolute_patch_locations_;
+ // Profile info used to generate new layout of files.
+ ProfileCompilationInfo* profile_compilation_info_;
+
DISALLOW_COPY_AND_ASSIGN(OatWriter);
};
diff --git a/compiler/optimizing/bounds_check_elimination_test.cc b/compiler/optimizing/bounds_check_elimination_test.cc
index b7c24ff..dfa1504 100644
--- a/compiler/optimizing/bounds_check_elimination_test.cc
+++ b/compiler/optimizing/bounds_check_elimination_test.cc
@@ -70,9 +70,9 @@
graph_->AddBlock(entry);
graph_->SetEntryBlock(entry);
HInstruction* parameter1 = new (&allocator_)
- HParameterValue(graph_->GetDexFile(), 0, 0, Primitive::kPrimNot); // array
+ HParameterValue(graph_->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimNot); // array
HInstruction* parameter2 = new (&allocator_)
- HParameterValue(graph_->GetDexFile(), 0, 0, Primitive::kPrimInt); // i
+ HParameterValue(graph_->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimInt); // i
entry->AddInstruction(parameter1);
entry->AddInstruction(parameter2);
@@ -167,9 +167,9 @@
graph_->AddBlock(entry);
graph_->SetEntryBlock(entry);
HInstruction* parameter1 = new (&allocator_)
- HParameterValue(graph_->GetDexFile(), 0, 0, Primitive::kPrimNot); // array
+ HParameterValue(graph_->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimNot); // array
HInstruction* parameter2 = new (&allocator_)
- HParameterValue(graph_->GetDexFile(), 0, 0, Primitive::kPrimInt); // i
+ HParameterValue(graph_->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimInt); // i
entry->AddInstruction(parameter1);
entry->AddInstruction(parameter2);
@@ -231,9 +231,9 @@
graph_->AddBlock(entry);
graph_->SetEntryBlock(entry);
HInstruction* parameter1 = new (&allocator_)
- HParameterValue(graph_->GetDexFile(), 0, 0, Primitive::kPrimNot); // array
+ HParameterValue(graph_->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimNot); // array
HInstruction* parameter2 = new (&allocator_)
- HParameterValue(graph_->GetDexFile(), 0, 0, Primitive::kPrimInt); // i
+ HParameterValue(graph_->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimInt); // i
entry->AddInstruction(parameter1);
entry->AddInstruction(parameter2);
@@ -295,7 +295,7 @@
graph_->AddBlock(entry);
graph_->SetEntryBlock(entry);
HInstruction* parameter = new (&allocator_) HParameterValue(
- graph_->GetDexFile(), 0, 0, Primitive::kPrimNot);
+ graph_->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimNot);
entry->AddInstruction(parameter);
HInstruction* constant_5 = graph_->GetIntConstant(5);
@@ -364,7 +364,7 @@
graph->AddBlock(entry);
graph->SetEntryBlock(entry);
HInstruction* parameter = new (allocator) HParameterValue(
- graph->GetDexFile(), 0, 0, Primitive::kPrimNot);
+ graph->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimNot);
entry->AddInstruction(parameter);
HInstruction* constant_initial = graph->GetIntConstant(initial);
@@ -479,7 +479,7 @@
graph->AddBlock(entry);
graph->SetEntryBlock(entry);
HInstruction* parameter = new (allocator) HParameterValue(
- graph->GetDexFile(), 0, 0, Primitive::kPrimNot);
+ graph->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimNot);
entry->AddInstruction(parameter);
HInstruction* constant_initial = graph->GetIntConstant(initial);
@@ -600,7 +600,7 @@
constant_10,
graph->GetCurrentMethod(),
0,
- Primitive::kPrimInt,
+ dex::TypeIndex(static_cast<uint16_t>(Primitive::kPrimInt)),
graph->GetDexFile(),
kQuickAllocArray);
block->AddInstruction(new_array);
@@ -692,7 +692,7 @@
graph->AddBlock(entry);
graph->SetEntryBlock(entry);
HInstruction* parameter = new (allocator) HParameterValue(
- graph->GetDexFile(), 0, 0, Primitive::kPrimNot);
+ graph->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimNot);
entry->AddInstruction(parameter);
HInstruction* constant_initial = graph->GetIntConstant(initial);
@@ -795,7 +795,7 @@
graph_->AddBlock(entry);
graph_->SetEntryBlock(entry);
HInstruction* parameter = new (&allocator_) HParameterValue(
- graph_->GetDexFile(), 0, 0, Primitive::kPrimNot);
+ graph_->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimNot);
entry->AddInstruction(parameter);
HInstruction* constant_0 = graph_->GetIntConstant(0);
diff --git a/compiler/optimizing/code_generator.cc b/compiler/optimizing/code_generator.cc
index 8b450e1..9f6b78a 100644
--- a/compiler/optimizing/code_generator.cc
+++ b/compiler/optimizing/code_generator.cc
@@ -1375,4 +1375,33 @@
return klass->GetDisableIntrinsicFlagOffset().Uint32Value();
}
+void CodeGenerator::EmitJitRoots(uint8_t* code,
+ Handle<mirror::ObjectArray<mirror::Object>> roots,
+ const uint8_t* roots_data,
+ Handle<mirror::DexCache> outer_dex_cache) {
+ DCHECK_EQ(static_cast<size_t>(roots->GetLength()), GetNumberOfJitRoots());
+ StackHandleScope<1> hs(Thread::Current());
+ MutableHandle<mirror::DexCache> h_dex_cache(hs.NewHandle<mirror::DexCache>(nullptr));
+ ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+ size_t index = 0;
+ for (auto& entry : jit_string_roots_) {
+ const DexFile& entry_dex_file = *entry.first.dex_file;
+ // Avoid the expensive FindDexCache call by checking if the string is
+ // in the compiled method's dex file.
+ h_dex_cache.Assign(IsSameDexFile(*outer_dex_cache->GetDexFile(), entry_dex_file)
+ ? outer_dex_cache.Get()
+ : class_linker->FindDexCache(hs.Self(), entry_dex_file));
+ mirror::String* string = class_linker->LookupString(
+ entry_dex_file, entry.first.string_index, h_dex_cache);
+ DCHECK(string != nullptr) << "JIT roots require strings to have been loaded";
+ // Ensure the string is strongly interned. This is a requirement on how the JIT
+ // handles strings. b/32995596
+ class_linker->GetInternTable()->InternStrong(string);
+ roots->Set(index, string);
+ entry.second = index;
+ ++index;
+ }
+ EmitJitRootPatches(code, roots_data);
+}
+
} // namespace art
diff --git a/compiler/optimizing/code_generator.h b/compiler/optimizing/code_generator.h
index bf246ad..a5d19ab 100644
--- a/compiler/optimizing/code_generator.h
+++ b/compiler/optimizing/code_generator.h
@@ -32,6 +32,7 @@
#include "optimizing_compiler_stats.h"
#include "read_barrier_option.h"
#include "stack_map_stream.h"
+#include "string_reference.h"
#include "utils/label.h"
namespace art {
@@ -335,6 +336,17 @@
void BuildStackMaps(MemoryRegion region, const DexFile::CodeItem& code_item);
size_t ComputeStackMapsSize();
+ size_t GetNumberOfJitRoots() const {
+ return jit_string_roots_.size();
+ }
+
+ // Fills the `literals` array with literals collected during code generation.
+ // Also emits literal patches.
+ void EmitJitRoots(uint8_t* code,
+ Handle<mirror::ObjectArray<mirror::Object>> roots,
+ const uint8_t* roots_data,
+ Handle<mirror::DexCache> outer_dex_cache)
+ REQUIRES_SHARED(Locks::mutator_lock_);
bool IsLeafMethod() const {
return is_leaf_;
@@ -515,6 +527,26 @@
virtual HLoadClass::LoadKind GetSupportedLoadClassKind(
HLoadClass::LoadKind desired_class_load_kind) = 0;
+ static LocationSummary::CallKind GetLoadStringCallKind(HLoadString* load) {
+ switch (load->GetLoadKind()) {
+ case HLoadString::LoadKind::kBssEntry:
+ DCHECK(load->NeedsEnvironment());
+ return LocationSummary::kCallOnSlowPath;
+ case HLoadString::LoadKind::kDexCacheViaMethod:
+ DCHECK(load->NeedsEnvironment());
+ return LocationSummary::kCallOnMainOnly;
+ case HLoadString::LoadKind::kJitTableAddress:
+ DCHECK(!load->NeedsEnvironment());
+ return kEmitCompilerReadBarrier
+ ? LocationSummary::kCallOnSlowPath
+ : LocationSummary::kNoCall;
+ break;
+ default:
+ DCHECK(!load->NeedsEnvironment());
+ return LocationSummary::kNoCall;
+ }
+ }
+
// Check if the desired_dispatch_info is supported. If it is, return it,
// otherwise return a fall-back info that should be used instead.
virtual HInvokeStaticOrDirect::DispatchInfo GetSupportedInvokeStaticOrDirectDispatch(
@@ -571,6 +603,8 @@
fpu_callee_save_mask_(fpu_callee_save_mask),
stack_map_stream_(graph->GetArena()),
block_order_(nullptr),
+ jit_string_roots_(StringReferenceValueComparator(),
+ graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
disasm_info_(nullptr),
stats_(stats),
graph_(graph),
@@ -637,6 +671,12 @@
return current_slow_path_;
}
+ // Emit the patches assocatied with JIT roots. Only applies to JIT compiled code.
+ virtual void EmitJitRootPatches(uint8_t* code ATTRIBUTE_UNUSED,
+ const uint8_t* roots_data ATTRIBUTE_UNUSED) {
+ DCHECK_EQ(jit_string_roots_.size(), 0u);
+ }
+
// Frame size required for this method.
uint32_t frame_size_;
uint32_t core_spill_mask_;
@@ -662,6 +702,11 @@
// The order to use for code generation.
const ArenaVector<HBasicBlock*>* block_order_;
+ // Maps a StringReference (dex_file, string_index) to the index in the literal table.
+ // Entries are intially added with a 0 index, and `EmitJitRoots` will compute all the
+ // indices.
+ ArenaSafeMap<StringReference, size_t, StringReferenceValueComparator> jit_string_roots_;
+
DisassemblyInformation* disasm_info_;
private:
diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc
index c6363d1..8a6b94e 100644
--- a/compiler/optimizing/code_generator_arm.cc
+++ b/compiler/optimizing/code_generator_arm.cc
@@ -383,7 +383,7 @@
SaveLiveRegisters(codegen, locations);
InvokeRuntimeCallingConvention calling_convention;
- __ LoadImmediate(calling_convention.GetRegisterAt(0), cls_->GetTypeIndex());
+ __ LoadImmediate(calling_convention.GetRegisterAt(0), cls_->GetTypeIndex().index_);
QuickEntrypointEnum entrypoint = do_clinit_ ? kQuickInitializeStaticStorage
: kQuickInitializeType;
arm_codegen->InvokeRuntime(entrypoint, at_, dex_pc_, this);
@@ -1214,7 +1214,9 @@
graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
pc_relative_type_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
boot_image_address_patches_(std::less<uint32_t>(),
- graph->GetArena()->Adapter(kArenaAllocCodeGenerator)) {
+ graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
+ jit_string_patches_(StringReferenceValueComparator(),
+ graph->GetArena()->Adapter(kArenaAllocCodeGenerator)) {
// Always save the LR register to mimic Quick.
AddAllocatedRegister(Location::RegisterLocation(LR));
}
@@ -3951,7 +3953,7 @@
void InstructionCodeGeneratorARM::VisitNewArray(HNewArray* instruction) {
InvokeRuntimeCallingConvention calling_convention;
- __ LoadImmediate(calling_convention.GetRegisterAt(0), instruction->GetTypeIndex());
+ __ LoadImmediate(calling_convention.GetRegisterAt(0), instruction->GetTypeIndex().index_);
// Note: if heap poisoning is enabled, the entry point takes cares
// of poisoning the reference.
codegen_->InvokeRuntime(instruction->GetEntrypoint(), instruction, instruction->GetDexPc());
@@ -5741,7 +5743,7 @@
void InstructionCodeGeneratorARM::VisitLoadClass(HLoadClass* cls) {
LocationSummary* locations = cls->GetLocations();
if (cls->NeedsAccessCheck()) {
- codegen_->MoveConstant(locations->GetTemp(0), cls->GetTypeIndex());
+ codegen_->MoveConstant(locations->GetTemp(0), cls->GetTypeIndex().index_);
codegen_->InvokeRuntime(kQuickInitializeTypeAndVerifyAccess, cls, cls->GetDexPc());
CheckEntrypointTypes<kQuickInitializeTypeAndVerifyAccess, void*, uint32_t>();
return;
@@ -5828,7 +5830,7 @@
current_method,
ArtMethod::DexCacheResolvedTypesOffset(kArmPointerSize).Int32Value());
// /* GcRoot<mirror::Class> */ out = out[type_index]
- size_t offset = CodeGenerator::GetCacheOffset(cls->GetTypeIndex());
+ size_t offset = CodeGenerator::GetCacheOffset(cls->GetTypeIndex().index_);
GenerateGcRootFieldLoad(cls, out_loc, out, offset, read_barrier_option);
generate_null_check = !cls->IsInDexCache();
}
@@ -5893,6 +5895,9 @@
case HLoadString::LoadKind::kBssEntry:
DCHECK(!Runtime::Current()->UseJitCompilation());
break;
+ case HLoadString::LoadKind::kJitTableAddress:
+ DCHECK(Runtime::Current()->UseJitCompilation());
+ break;
case HLoadString::LoadKind::kDexCacheViaMethod:
break;
}
@@ -5900,13 +5905,8 @@
}
void LocationsBuilderARM::VisitLoadString(HLoadString* load) {
- LocationSummary::CallKind call_kind = load->NeedsEnvironment()
- ? ((load->GetLoadKind() == HLoadString::LoadKind::kDexCacheViaMethod)
- ? LocationSummary::kCallOnMainOnly
- : LocationSummary::kCallOnSlowPath)
- : LocationSummary::kNoCall;
+ LocationSummary::CallKind call_kind = CodeGenerator::GetLoadStringCallKind(load);
LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(load, call_kind);
-
HLoadString::LoadKind load_kind = load->GetLoadKind();
if (load_kind == HLoadString::LoadKind::kDexCacheViaMethod) {
locations->SetOut(Location::RegisterLocation(R0));
@@ -5979,6 +5979,13 @@
__ Bind(slow_path->GetExitLabel());
return;
}
+ case HLoadString::LoadKind::kJitTableAddress: {
+ __ LoadLiteral(out, codegen_->DeduplicateJitStringLiteral(load->GetDexFile(),
+ load->GetStringIndex()));
+ // /* GcRoot<mirror::String> */ out = *out
+ GenerateGcRootFieldLoad(load, out_loc, out, /* offset */ 0, kCompilerReadBarrierOption);
+ return;
+ }
default:
break;
}
@@ -6490,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>(),
@@ -7320,8 +7324,8 @@
}
CodeGeneratorARM::PcRelativePatchInfo* CodeGeneratorARM::NewPcRelativeTypePatch(
- const DexFile& dex_file, uint32_t type_index) {
- return NewPcRelativePatch(dex_file, type_index, &pc_relative_type_patches_);
+ const DexFile& dex_file, dex::TypeIndex type_index) {
+ return NewPcRelativePatch(dex_file, type_index.index_, &pc_relative_type_patches_);
}
CodeGeneratorARM::PcRelativePatchInfo* CodeGeneratorARM::NewPcRelativeDexCacheArrayPatch(
@@ -7343,7 +7347,7 @@
}
Literal* CodeGeneratorARM::DeduplicateBootImageTypeLiteral(const DexFile& dex_file,
- uint32_t type_index) {
+ dex::TypeIndex type_index) {
return boot_image_type_patches_.GetOrCreate(
TypeReference(&dex_file, type_index),
[this]() { return __ NewLiteral<uint32_t>(/* placeholder */ 0u); });
@@ -7359,6 +7363,14 @@
return DeduplicateUint32Literal(address, &uint32_literals_);
}
+Literal* CodeGeneratorARM::DeduplicateJitStringLiteral(const DexFile& dex_file,
+ uint32_t string_index) {
+ jit_string_roots_.Overwrite(StringReference(&dex_file, string_index), /* placeholder */ 0u);
+ return jit_string_patches_.GetOrCreate(
+ StringReference(&dex_file, string_index),
+ [this]() { return __ NewLiteral<uint32_t>(/* placeholder */ 0u); });
+}
+
template <LinkerPatch (*Factory)(size_t, const DexFile*, uint32_t, uint32_t)>
inline void CodeGeneratorARM::EmitPcRelativeLinkerPatches(
const ArenaDeque<PcRelativePatchInfo>& infos,
@@ -7440,7 +7452,7 @@
uint32_t literal_offset = literal->GetLabel()->Position();
linker_patches->push_back(LinkerPatch::TypePatch(literal_offset,
target_type.dex_file,
- target_type.type_index));
+ target_type.type_index.index_));
}
EmitPcRelativeLinkerPatches<LinkerPatch::RelativeTypePatch>(pc_relative_type_patches_,
linker_patches);
@@ -7675,6 +7687,21 @@
}
}
+void CodeGeneratorARM::EmitJitRootPatches(uint8_t* code, const uint8_t* roots_data) {
+ for (const auto& entry : jit_string_patches_) {
+ const auto& it = jit_string_roots_.find(entry.first);
+ DCHECK(it != jit_string_roots_.end());
+ size_t index_in_table = it->second;
+ Literal* literal = entry.second;
+ DCHECK(literal->GetLabel()->IsBound());
+ uint32_t literal_offset = literal->GetLabel()->Position();
+ uintptr_t address =
+ reinterpret_cast<uintptr_t>(roots_data) + index_in_table * sizeof(GcRoot<mirror::Object>);
+ uint8_t* data = code + literal_offset;
+ reinterpret_cast<uint32_t*>(data)[0] = dchecked_integral_cast<uint32_t>(address);
+ }
+}
+
#undef __
#undef QUICK_ENTRY_POINT
diff --git a/compiler/optimizing/code_generator_arm.h b/compiler/optimizing/code_generator_arm.h
index f95dd57..a4ccb57 100644
--- a/compiler/optimizing/code_generator_arm.h
+++ b/compiler/optimizing/code_generator_arm.h
@@ -19,6 +19,7 @@
#include "base/enums.h"
#include "code_generator.h"
+#include "dex_file_types.h"
#include "driver/compiler_options.h"
#include "nodes.h"
#include "string_reference.h"
@@ -481,16 +482,19 @@
};
PcRelativePatchInfo* NewPcRelativeStringPatch(const DexFile& dex_file, uint32_t string_index);
- PcRelativePatchInfo* NewPcRelativeTypePatch(const DexFile& dex_file, uint32_t type_index);
+ PcRelativePatchInfo* NewPcRelativeTypePatch(const DexFile& dex_file, dex::TypeIndex type_index);
PcRelativePatchInfo* NewPcRelativeDexCacheArrayPatch(const DexFile& dex_file,
uint32_t element_offset);
Literal* DeduplicateBootImageStringLiteral(const DexFile& dex_file, uint32_t string_index);
- Literal* DeduplicateBootImageTypeLiteral(const DexFile& dex_file, uint32_t type_index);
+ Literal* DeduplicateBootImageTypeLiteral(const DexFile& dex_file, dex::TypeIndex type_index);
Literal* DeduplicateBootImageAddressLiteral(uint32_t address);
Literal* DeduplicateDexCacheAddressLiteral(uint32_t address);
+ Literal* DeduplicateJitStringLiteral(const DexFile& dex_file, uint32_t string_index);
void EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patches) OVERRIDE;
+ void EmitJitRootPatches(uint8_t* code, const uint8_t* roots_data) OVERRIDE;
+
// Fast path implementation of ReadBarrier::Barrier for a heap
// reference field load when Baker's read barriers are used.
void GenerateFieldLoadWithBakerReadBarrier(HInstruction* instruction,
@@ -591,9 +595,9 @@
using Uint32ToLiteralMap = ArenaSafeMap<uint32_t, Literal*>;
using MethodToLiteralMap = ArenaSafeMap<MethodReference, Literal*, MethodReferenceComparator>;
- using BootStringToLiteralMap = ArenaSafeMap<StringReference,
- Literal*,
- StringReferenceValueComparator>;
+ using StringToLiteralMap = ArenaSafeMap<StringReference,
+ Literal*,
+ StringReferenceValueComparator>;
using BootTypeToLiteralMap = ArenaSafeMap<TypeReference,
Literal*,
TypeReferenceValueComparator>;
@@ -605,7 +609,6 @@
PcRelativePatchInfo* NewPcRelativePatch(const DexFile& dex_file,
uint32_t offset_or_index,
ArenaDeque<PcRelativePatchInfo>* patches);
-
template <LinkerPatch (*Factory)(size_t, const DexFile*, uint32_t, uint32_t)>
static void EmitPcRelativeLinkerPatches(const ArenaDeque<PcRelativePatchInfo>& infos,
ArenaVector<LinkerPatch>* linker_patches);
@@ -630,7 +633,7 @@
// PC-relative patch info for each HArmDexCacheArraysBase.
ArenaDeque<PcRelativePatchInfo> pc_relative_dex_cache_patches_;
// Deduplication map for boot string literals for kBootImageLinkTimeAddress.
- BootStringToLiteralMap boot_image_string_patches_;
+ StringToLiteralMap boot_image_string_patches_;
// PC-relative String patch info; type depends on configuration (app .bss or boot image PIC).
ArenaDeque<PcRelativePatchInfo> pc_relative_string_patches_;
// Deduplication map for boot type literals for kBootImageLinkTimeAddress.
@@ -640,6 +643,9 @@
// Deduplication map for patchable boot image addresses.
Uint32ToLiteralMap boot_image_address_patches_;
+ // Patches for string literals in JIT compiled code.
+ StringToLiteralMap jit_string_patches_;
+
DISALLOW_COPY_AND_ASSIGN(CodeGeneratorARM);
};
diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc
index 4ab6065..a78b3da 100644
--- a/compiler/optimizing/code_generator_arm64.cc
+++ b/compiler/optimizing/code_generator_arm64.cc
@@ -288,7 +288,7 @@
SaveLiveRegisters(codegen, locations);
InvokeRuntimeCallingConvention calling_convention;
- __ Mov(calling_convention.GetRegisterAt(0).W(), cls_->GetTypeIndex());
+ __ Mov(calling_convention.GetRegisterAt(0).W(), cls_->GetTypeIndex().index_);
QuickEntrypointEnum entrypoint = do_clinit_ ? kQuickInitializeStaticStorage
: kQuickInitializeType;
arm64_codegen->InvokeRuntime(entrypoint, at_, dex_pc_, this);
@@ -572,8 +572,10 @@
// We are about to use the assembler to place literals directly. Make sure we have enough
// underlying code buffer and we have generated the jump table with right size.
- CodeBufferCheckScope scope(codegen->GetVIXLAssembler(), num_entries * sizeof(int32_t),
- CodeBufferCheckScope::kCheck, CodeBufferCheckScope::kExactSize);
+ vixl::CodeBufferCheckScope scope(codegen->GetVIXLAssembler(),
+ num_entries * sizeof(int32_t),
+ vixl::CodeBufferCheckScope::kReserveBufferSpace,
+ vixl::CodeBufferCheckScope::kExactSize);
__ Bind(&table_start_);
const ArenaVector<HBasicBlock*>& successors = switch_instr_->GetBlock()->GetSuccessors();
@@ -1158,7 +1160,9 @@
graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
pc_relative_type_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
boot_image_address_patches_(std::less<uint32_t>(),
- graph->GetArena()->Adapter(kArenaAllocCodeGenerator)) {
+ graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
+ jit_string_patches_(StringReferenceValueComparator(),
+ graph->GetArena()->Adapter(kArenaAllocCodeGenerator)) {
// Save the link register (containing the return address) to mimic Quick.
AddAllocatedRegister(LocationFrom(lr));
}
@@ -2258,10 +2262,10 @@
masm->GetCursorAddress<vixl::aarch64::Instruction*>() - kInstructionSize;
if (prev->IsLoadOrStore()) {
// Make sure we emit only exactly one nop.
- vixl::aarch64::CodeBufferCheckScope scope(masm,
- kInstructionSize,
- vixl::aarch64::CodeBufferCheckScope::kCheck,
- vixl::aarch64::CodeBufferCheckScope::kExactSize);
+ vixl::CodeBufferCheckScope scope(masm,
+ kInstructionSize,
+ vixl::CodeBufferCheckScope::kReserveBufferSpace,
+ vixl::CodeBufferCheckScope::kExactSize);
__ nop();
}
}
@@ -3802,12 +3806,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());
@@ -4037,7 +4038,8 @@
vixl::aarch64::Label* label = &relative_call_patches_.back().label;
SingleEmissionCheckScope guard(GetVIXLAssembler());
__ Bind(label);
- __ bl(0); // Branch and link to itself. This will be overriden at link time.
+ // Branch and link to itself. This will be overriden at link time.
+ __ bl(static_cast<int64_t>(0));
break;
}
case HInvokeStaticOrDirect::CodePtrLocation::kCallDirectWithFixup:
@@ -4103,9 +4105,9 @@
vixl::aarch64::Label* CodeGeneratorARM64::NewPcRelativeTypePatch(
const DexFile& dex_file,
- uint32_t type_index,
+ dex::TypeIndex type_index,
vixl::aarch64::Label* adrp_label) {
- return NewPcRelativePatch(dex_file, type_index, adrp_label, &pc_relative_type_patches_);
+ return NewPcRelativePatch(dex_file, type_index.index_, adrp_label, &pc_relative_type_patches_);
}
vixl::aarch64::Label* CodeGeneratorARM64::NewPcRelativeDexCacheArrayPatch(
@@ -4137,7 +4139,7 @@
}
vixl::aarch64::Literal<uint32_t>* CodeGeneratorARM64::DeduplicateBootImageTypeLiteral(
- const DexFile& dex_file, uint32_t type_index) {
+ const DexFile& dex_file, dex::TypeIndex type_index) {
return boot_image_type_patches_.GetOrCreate(
TypeReference(&dex_file, type_index),
[this]() { return __ CreateLiteralDestroyedWithPool<uint32_t>(/* placeholder */ 0u); });
@@ -4155,12 +4157,20 @@
return DeduplicateUint64Literal(address);
}
+vixl::aarch64::Literal<uint32_t>* CodeGeneratorARM64::DeduplicateJitStringLiteral(
+ const DexFile& dex_file, uint32_t string_index) {
+ jit_string_roots_.Overwrite(StringReference(&dex_file, string_index), /* placeholder */ 0u);
+ return jit_string_patches_.GetOrCreate(
+ StringReference(&dex_file, string_index),
+ [this]() { return __ CreateLiteralDestroyedWithPool<uint32_t>(/* placeholder */ 0u); });
+}
+
void CodeGeneratorARM64::EmitAdrpPlaceholder(vixl::aarch64::Label* fixup_label,
vixl::aarch64::Register reg) {
DCHECK(reg.IsX());
SingleEmissionCheckScope guard(GetVIXLAssembler());
__ Bind(fixup_label);
- __ adrp(reg, /* offset placeholder */ 0);
+ __ adrp(reg, /* offset placeholder */ static_cast<int64_t>(0));
}
void CodeGeneratorARM64::EmitAddPlaceholder(vixl::aarch64::Label* fixup_label,
@@ -4250,7 +4260,7 @@
vixl::aarch64::Literal<uint32_t>* literal = entry.second;
linker_patches->push_back(LinkerPatch::TypePatch(literal->GetOffset(),
target_type.dex_file,
- target_type.type_index));
+ target_type.type_index.index_));
}
EmitPcRelativeLinkerPatches<LinkerPatch::RelativeTypePatch>(pc_relative_type_patches_,
linker_patches);
@@ -4374,7 +4384,7 @@
void InstructionCodeGeneratorARM64::VisitLoadClass(HLoadClass* cls) {
if (cls->NeedsAccessCheck()) {
- codegen_->MoveConstant(cls->GetLocations()->GetTemp(0), cls->GetTypeIndex());
+ codegen_->MoveConstant(cls->GetLocations()->GetTemp(0), cls->GetTypeIndex().index_);
codegen_->InvokeRuntime(kQuickInitializeTypeAndVerifyAccess, cls, cls->GetDexPc());
CheckEntrypointTypes<kQuickInitializeTypeAndVerifyAccess, void*, uint32_t>();
return;
@@ -4410,7 +4420,7 @@
DCHECK_EQ(read_barrier_option, kWithoutReadBarrier);
// Add ADRP with its PC-relative type patch.
const DexFile& dex_file = cls->GetDexFile();
- uint32_t type_index = cls->GetTypeIndex();
+ dex::TypeIndex type_index = cls->GetTypeIndex();
vixl::aarch64::Label* adrp_label = codegen_->NewPcRelativeTypePatch(dex_file, type_index);
codegen_->EmitAdrpPlaceholder(adrp_label, out.X());
// Add ADD with its PC-relative type patch.
@@ -4478,7 +4488,7 @@
GenerateGcRootFieldLoad(cls,
out_loc,
out.X(),
- CodeGenerator::GetCacheOffset(cls->GetTypeIndex()),
+ CodeGenerator::GetCacheOffset(cls->GetTypeIndex().index_),
/* fixup_label */ nullptr,
read_barrier_option);
generate_null_check = !cls->IsInDexCache();
@@ -4540,16 +4550,15 @@
break;
case HLoadString::LoadKind::kDexCacheViaMethod:
break;
+ case HLoadString::LoadKind::kJitTableAddress:
+ DCHECK(Runtime::Current()->UseJitCompilation());
+ break;
}
return desired_string_load_kind;
}
void LocationsBuilderARM64::VisitLoadString(HLoadString* load) {
- LocationSummary::CallKind call_kind = load->NeedsEnvironment()
- ? ((load->GetLoadKind() == HLoadString::LoadKind::kDexCacheViaMethod)
- ? LocationSummary::kCallOnMainOnly
- : LocationSummary::kCallOnSlowPath)
- : LocationSummary::kNoCall;
+ LocationSummary::CallKind call_kind = CodeGenerator::GetLoadStringCallKind(load);
LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(load, call_kind);
if (load->GetLoadKind() == HLoadString::LoadKind::kDexCacheViaMethod) {
InvokeRuntimeCallingConvention calling_convention;
@@ -4575,6 +4584,7 @@
void InstructionCodeGeneratorARM64::VisitLoadString(HLoadString* load) {
Register out = OutputRegister(load);
+ Location out_loc = load->GetLocations()->Out();
switch (load->GetLoadKind()) {
case HLoadString::LoadKind::kBootImageLinkTimeAddress:
@@ -4611,9 +4621,9 @@
// Add LDR with its PC-relative String patch.
vixl::aarch64::Label* ldr_label =
codegen_->NewPcRelativeStringPatch(dex_file, string_index, adrp_label);
- // /* GcRoot<mirror::Class> */ out = *(base_address + offset) /* PC-relative */
+ // /* GcRoot<mirror::String> */ out = *(base_address + offset) /* PC-relative */
GenerateGcRootFieldLoad(load,
- load->GetLocations()->Out(),
+ out_loc,
temp,
/* offset placeholder */ 0u,
ldr_label,
@@ -4625,6 +4635,17 @@
__ Bind(slow_path->GetExitLabel());
return;
}
+ case HLoadString::LoadKind::kJitTableAddress: {
+ __ Ldr(out, codegen_->DeduplicateJitStringLiteral(load->GetDexFile(),
+ load->GetStringIndex()));
+ GenerateGcRootFieldLoad(load,
+ out_loc,
+ out.X(),
+ /* offset */ 0,
+ /* fixup_label */ nullptr,
+ kCompilerReadBarrierOption);
+ return;
+ }
default:
break;
}
@@ -4757,7 +4778,7 @@
InvokeRuntimeCallingConvention calling_convention;
Register type_index = RegisterFrom(locations->GetTemp(0), Primitive::kPrimInt);
DCHECK(type_index.Is(w0));
- __ Mov(type_index, instruction->GetTypeIndex());
+ __ Mov(type_index, instruction->GetTypeIndex().index_);
// Note: if heap poisoning is enabled, the entry point takes cares
// of poisoning the reference.
codegen_->InvokeRuntime(instruction->GetEntrypoint(), instruction, instruction->GetDexPc());
@@ -5744,7 +5765,19 @@
}
}
-
+void CodeGeneratorARM64::EmitJitRootPatches(uint8_t* code, const uint8_t* roots_data) {
+ for (const auto& entry : jit_string_patches_) {
+ const auto& it = jit_string_roots_.find(entry.first);
+ DCHECK(it != jit_string_roots_.end());
+ size_t index_in_table = it->second;
+ vixl::aarch64::Literal<uint32_t>* literal = entry.second;
+ uint32_t literal_offset = literal->GetOffset();
+ uintptr_t address =
+ reinterpret_cast<uintptr_t>(roots_data) + index_in_table * sizeof(GcRoot<mirror::Object>);
+ uint8_t* data = code + literal_offset;
+ reinterpret_cast<uint32_t*>(data)[0] = dchecked_integral_cast<uint32_t>(address);
+ }
+}
#undef __
#undef QUICK_ENTRY_POINT
diff --git a/compiler/optimizing/code_generator_arm64.h b/compiler/optimizing/code_generator_arm64.h
index 0e8d4fd..1545fd3 100644
--- a/compiler/optimizing/code_generator_arm64.h
+++ b/compiler/optimizing/code_generator_arm64.h
@@ -20,6 +20,7 @@
#include "arch/arm64/quick_method_frame_info_arm64.h"
#include "code_generator.h"
#include "common_arm64.h"
+#include "dex_file_types.h"
#include "driver/compiler_options.h"
#include "nodes.h"
#include "parallel_move_resolver.h"
@@ -547,7 +548,7 @@
// ADRP (pass `adrp_label = null`) or the ADD (pass `adrp_label` pointing
// to the associated ADRP patch label).
vixl::aarch64::Label* NewPcRelativeTypePatch(const DexFile& dex_file,
- uint32_t type_index,
+ dex::TypeIndex type_index,
vixl::aarch64::Label* adrp_label = nullptr);
// Add a new PC-relative dex cache array patch for an instruction and return
@@ -562,9 +563,11 @@
vixl::aarch64::Literal<uint32_t>* DeduplicateBootImageStringLiteral(const DexFile& dex_file,
uint32_t string_index);
vixl::aarch64::Literal<uint32_t>* DeduplicateBootImageTypeLiteral(const DexFile& dex_file,
- uint32_t type_index);
+ dex::TypeIndex type_index);
vixl::aarch64::Literal<uint32_t>* DeduplicateBootImageAddressLiteral(uint64_t address);
vixl::aarch64::Literal<uint64_t>* DeduplicateDexCacheAddressLiteral(uint64_t address);
+ vixl::aarch64::Literal<uint32_t>* DeduplicateJitStringLiteral(const DexFile& dex_file,
+ uint32_t string_index);
void EmitAdrpPlaceholder(vixl::aarch64::Label* fixup_label, vixl::aarch64::Register reg);
void EmitAddPlaceholder(vixl::aarch64::Label* fixup_label,
@@ -576,6 +579,8 @@
void EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patches) OVERRIDE;
+ void EmitJitRootPatches(uint8_t* code, const uint8_t* roots_data) OVERRIDE;
+
// Fast path implementation of ReadBarrier::Barrier for a heap
// reference field load when Baker's read barriers are used.
void GenerateFieldLoadWithBakerReadBarrier(HInstruction* instruction,
@@ -673,9 +678,9 @@
using MethodToLiteralMap = ArenaSafeMap<MethodReference,
vixl::aarch64::Literal<uint64_t>*,
MethodReferenceComparator>;
- using BootStringToLiteralMap = ArenaSafeMap<StringReference,
- vixl::aarch64::Literal<uint32_t>*,
- StringReferenceValueComparator>;
+ using StringToLiteralMap = ArenaSafeMap<StringReference,
+ vixl::aarch64::Literal<uint32_t>*,
+ StringReferenceValueComparator>;
using BootTypeToLiteralMap = ArenaSafeMap<TypeReference,
vixl::aarch64::Literal<uint32_t>*,
TypeReferenceValueComparator>;
@@ -739,7 +744,7 @@
// PC-relative DexCache access info.
ArenaDeque<PcRelativePatchInfo> pc_relative_dex_cache_patches_;
// Deduplication map for boot string literals for kBootImageLinkTimeAddress.
- BootStringToLiteralMap boot_image_string_patches_;
+ StringToLiteralMap boot_image_string_patches_;
// PC-relative String patch info; type depends on configuration (app .bss or boot image PIC).
ArenaDeque<PcRelativePatchInfo> pc_relative_string_patches_;
// Deduplication map for boot type literals for kBootImageLinkTimeAddress.
@@ -749,6 +754,9 @@
// Deduplication map for patchable boot image addresses.
Uint32ToLiteralMap boot_image_address_patches_;
+ // Patches for string literals in JIT compiled code.
+ StringToLiteralMap jit_string_patches_;
+
DISALLOW_COPY_AND_ASSIGN(CodeGeneratorARM64);
};
diff --git a/compiler/optimizing/code_generator_arm_vixl.cc b/compiler/optimizing/code_generator_arm_vixl.cc
index e9827e8..e399f32 100644
--- a/compiler/optimizing/code_generator_arm_vixl.cc
+++ b/compiler/optimizing/code_generator_arm_vixl.cc
@@ -47,6 +47,7 @@
using helpers::InputRegisterAt;
using helpers::InputSRegisterAt;
using helpers::InputVRegisterAt;
+using helpers::Int32ConstantFrom;
using helpers::LocationFrom;
using helpers::LowRegisterFrom;
using helpers::LowSRegisterFrom;
@@ -132,7 +133,7 @@
vixl32::Register base = sp;
if (stack_offset != 0) {
base = temps.Acquire();
- __ Add(base, sp, stack_offset);
+ __ Add(base, sp, Operand::From(stack_offset));
}
__ Vstm(F64, base, NO_WRITE_BACK, DRegisterList(d_reg, number_of_d_regs));
}
@@ -180,7 +181,7 @@
vixl32::Register base = sp;
if (stack_offset != 0) {
base = temps.Acquire();
- __ Add(base, sp, stack_offset);
+ __ Add(base, sp, Operand::From(stack_offset));
}
__ Vldm(F64, base, NO_WRITE_BACK, DRegisterList(d_reg, number_of_d_regs));
}
@@ -398,7 +399,7 @@
SaveLiveRegisters(codegen, locations);
InvokeRuntimeCallingConventionARMVIXL calling_convention;
- __ Mov(calling_convention.GetRegisterAt(0), cls_->GetTypeIndex());
+ __ Mov(calling_convention.GetRegisterAt(0), cls_->GetTypeIndex().index_);
QuickEntrypointEnum entrypoint = do_clinit_ ? kQuickInitializeStaticStorage
: kQuickInitializeType;
arm_codegen->InvokeRuntime(entrypoint, at_, dex_pc_, this);
@@ -673,13 +674,22 @@
DCHECK_GE(num_entries, kPackedSwitchCompareJumpThreshold);
// We are about to use the assembler to place literals directly. Make sure we have enough
- // underlying code buffer and we have generated the jump table with right size.
- codegen->GetVIXLAssembler()->GetBuffer().Align();
+ // underlying code buffer and we have generated a jump table of the right size, using
+ // codegen->GetVIXLAssembler()->GetBuffer().Align();
AssemblerAccurateScope aas(codegen->GetVIXLAssembler(),
num_entries * sizeof(int32_t),
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 +701,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);
}
@@ -1143,7 +1153,8 @@
void InstructionCodeGeneratorARMVIXL::GenerateTestAndBranch(HInstruction* instruction,
size_t condition_input_index,
vixl32::Label* true_target,
- vixl32::Label* false_target) {
+ vixl32::Label* false_target,
+ bool far_target) {
HInstruction* cond = instruction->InputAt(condition_input_index);
if (true_target == nullptr && false_target == nullptr) {
@@ -1179,9 +1190,13 @@
DCHECK(cond_val.IsRegister());
}
if (true_target == nullptr) {
- __ Cbz(InputRegisterAt(instruction, condition_input_index), false_target);
+ __ CompareAndBranchIfZero(InputRegisterAt(instruction, condition_input_index),
+ false_target,
+ far_target);
} else {
- __ Cbnz(InputRegisterAt(instruction, condition_input_index), true_target);
+ __ CompareAndBranchIfNonZero(InputRegisterAt(instruction, condition_input_index),
+ true_target,
+ far_target);
}
} else {
// Condition has not been materialized. Use its inputs as the comparison and
@@ -1276,7 +1291,8 @@
GenerateTestAndBranch(select,
/* condition_input_index */ 2,
/* true_target */ nullptr,
- &false_target);
+ &false_target,
+ /* far_target */ false);
codegen_->MoveLocation(locations->Out(), locations->InAt(1), select->GetType());
__ Bind(&false_target);
}
@@ -1652,7 +1668,20 @@
// Set the hidden (in r12) argument. It is done here, right before a BLX to prevent other
// instruction from clobbering it as they might use r12 as a scratch register.
DCHECK(hidden_reg.Is(r12));
- __ Mov(hidden_reg, invoke->GetDexMethodIndex());
+
+ {
+ // The VIXL macro assembler may clobber any of the scratch registers that are available to it,
+ // so it checks if the application is using them (by passing them to the macro assembler
+ // methods). The following application of UseScratchRegisterScope corrects VIXL's notion of
+ // what is available, and is the opposite of the standard usage: Instead of requesting a
+ // temporary location, it imposes an external constraint (i.e. a specific register is reserved
+ // for the hidden argument). Note that this works even if VIXL needs a scratch register itself
+ // (to materialize the constant), since the destination register becomes available for such use
+ // internally for the duration of the macro instruction.
+ UseScratchRegisterScope temps(GetVIXLAssembler());
+ temps.Exclude(hidden_reg);
+ __ Mov(hidden_reg, invoke->GetDexMethodIndex());
+ }
{
AssemblerAccurateScope aas(GetVIXLAssembler(),
@@ -2016,7 +2045,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 +2053,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 +2129,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 +2160,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 +2168,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)
@@ -2446,13 +2472,13 @@
vixl32::Register dividend = InputRegisterAt(instruction, 0);
vixl32::Register temp1 = RegisterFrom(locations->GetTemp(0));
vixl32::Register temp2 = RegisterFrom(locations->GetTemp(1));
- int64_t imm = second.GetConstant()->AsIntConstant()->GetValue();
+ int32_t imm = Int32ConstantFrom(second);
int64_t magic;
int shift;
CalculateMagicAndShiftForDivRem(imm, false /* is_long */, &magic, &shift);
- __ Mov(temp1, magic);
+ __ Mov(temp1, Operand::From(magic));
__ Smull(temp2, temp1, dividend, temp1);
if (imm > 0 && magic < 0) {
@@ -2769,7 +2795,7 @@
case Primitive::kPrimShort:
case Primitive::kPrimInt: {
if (value.IsRegister()) {
- __ Cbz(InputRegisterAt(instruction, 0), slow_path->GetEntryLabel());
+ __ CompareAndBranchIfZero(InputRegisterAt(instruction, 0), slow_path->GetEntryLabel());
} else {
DCHECK(value.IsConstant()) << value;
if (value.GetConstant()->AsIntConstant()->GetValue() == 0) {
@@ -2845,9 +2871,9 @@
}
// Rotate, or mov to out for zero or word size rotations.
if (rot != 0u) {
- __ Lsr(out_reg_hi, in_reg_hi, rot);
+ __ Lsr(out_reg_hi, in_reg_hi, Operand::From(rot));
__ Orr(out_reg_hi, out_reg_hi, Operand(in_reg_lo, ShiftType::LSL, kArmBitsPerWord - rot));
- __ Lsr(out_reg_lo, in_reg_lo, rot);
+ __ Lsr(out_reg_lo, in_reg_lo, Operand::From(rot));
__ Orr(out_reg_lo, out_reg_lo, Operand(in_reg_hi, ShiftType::LSL, kArmBitsPerWord - rot));
} else {
__ Mov(out_reg_lo, in_reg_lo);
@@ -2862,7 +2888,7 @@
__ And(shift_right, RegisterFrom(rhs), 0x1F);
__ Lsrs(shift_left, RegisterFrom(rhs), 6);
// TODO(VIXL): Check that flags are kept after "vixl32::LeaveFlags" enabled.
- __ Rsb(shift_left, shift_right, kArmBitsPerWord);
+ __ Rsb(shift_left, shift_right, Operand::From(kArmBitsPerWord));
__ B(cc, &shift_by_32_plus_shift_right);
// out_reg_hi = (reg_hi << shift_left) | (reg_lo >> shift_right).
@@ -3028,11 +3054,11 @@
// Shift the high part
__ Lsl(o_h, high, o_l);
// Shift the low part and `or` what overflew on the high part
- __ Rsb(temp, o_l, kArmBitsPerWord);
+ __ Rsb(temp, o_l, Operand::From(kArmBitsPerWord));
__ Lsr(temp, low, temp);
__ Orr(o_h, o_h, temp);
// If the shift is > 32 bits, override the high part
- __ Subs(temp, o_l, kArmBitsPerWord);
+ __ Subs(temp, o_l, Operand::From(kArmBitsPerWord));
{
AssemblerAccurateScope guard(GetVIXLAssembler(),
3 * kArmInstrMaxSizeInBytes,
@@ -3047,11 +3073,11 @@
// Shift the low part
__ Lsr(o_l, low, o_h);
// Shift the high part and `or` what underflew on the low part
- __ Rsb(temp, o_h, kArmBitsPerWord);
+ __ Rsb(temp, o_h, Operand::From(kArmBitsPerWord));
__ Lsl(temp, high, temp);
__ Orr(o_l, o_l, temp);
// If the shift is > 32 bits, override the low part
- __ Subs(temp, o_h, kArmBitsPerWord);
+ __ Subs(temp, o_h, Operand::From(kArmBitsPerWord));
{
AssemblerAccurateScope guard(GetVIXLAssembler(),
3 * kArmInstrMaxSizeInBytes,
@@ -3065,10 +3091,10 @@
__ And(o_h, second_reg, kMaxLongShiftDistance);
// same as Shr except we use `Lsr`s and not `Asr`s
__ Lsr(o_l, low, o_h);
- __ Rsb(temp, o_h, kArmBitsPerWord);
+ __ Rsb(temp, o_h, Operand::From(kArmBitsPerWord));
__ Lsl(temp, high, temp);
__ Orr(o_l, o_l, temp);
- __ Subs(temp, o_h, kArmBitsPerWord);
+ __ Subs(temp, o_h, Operand::From(kArmBitsPerWord));
{
AssemblerAccurateScope guard(GetVIXLAssembler(),
3 * kArmInstrMaxSizeInBytes,
@@ -3211,7 +3237,7 @@
void InstructionCodeGeneratorARMVIXL::VisitNewArray(HNewArray* instruction) {
InvokeRuntimeCallingConventionARMVIXL calling_convention;
- __ Mov(calling_convention.GetRegisterAt(0), instruction->GetTypeIndex());
+ __ Mov(calling_convention.GetRegisterAt(0), instruction->GetTypeIndex().index_);
// Note: if heap poisoning is enabled, the entry point takes cares
// of poisoning the reference.
codegen_->InvokeRuntime(instruction->GetEntrypoint(), instruction, instruction->GetDexPc());
@@ -3412,7 +3438,7 @@
__ Add(temp, addr, offset);
addr = temp;
}
- __ Ldrexd(out_lo, out_hi, addr);
+ __ Ldrexd(out_lo, out_hi, MemOperand(addr));
}
void InstructionCodeGeneratorARMVIXL::GenerateWideAtomicStore(vixl32::Register addr,
@@ -3432,10 +3458,10 @@
__ Bind(&fail);
// We need a load followed by store. (The address used in a STREX instruction must
// be the same as the address in the most recently executed LDREX instruction.)
- __ Ldrexd(temp1, temp2, addr);
+ __ Ldrexd(temp1, temp2, MemOperand(addr));
codegen_->MaybeRecordImplicitNullCheck(instruction);
- __ Strexd(temp1, value_lo, value_hi, addr);
- __ Cbnz(temp1, &fail);
+ __ Strexd(temp1, value_lo, value_hi, MemOperand(addr));
+ __ CompareAndBranchIfNonZero(temp1, &fail);
}
void LocationsBuilderARMVIXL::HandleFieldSet(
@@ -3951,7 +3977,7 @@
NullCheckSlowPathARMVIXL* slow_path =
new (GetGraph()->GetArena()) NullCheckSlowPathARMVIXL(instruction);
AddSlowPath(slow_path);
- __ Cbz(InputRegisterAt(instruction, 0), slow_path->GetEntryLabel());
+ __ CompareAndBranchIfZero(InputRegisterAt(instruction, 0), slow_path->GetEntryLabel());
}
void InstructionCodeGeneratorARMVIXL::VisitNullCheck(HNullCheck* instruction) {
@@ -4164,7 +4190,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 +4242,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 +4377,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);
}
@@ -4386,7 +4433,7 @@
codegen_->AddSlowPath(slow_path);
if (instruction->GetValueCanBeNull()) {
vixl32::Label non_zero;
- __ Cbnz(value, &non_zero);
+ __ CompareAndBranchIfNonZero(value, &non_zero);
if (index.IsConstant()) {
size_t offset =
(index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
@@ -4434,7 +4481,7 @@
GetAssembler()->LoadFromOffset(kLoadWord, temp1, temp1, super_offset);
// If heap poisoning is enabled, no need to unpoison
// `temp1`, as we are comparing against null below.
- __ Cbnz(temp1, slow_path->GetEntryLabel());
+ __ CompareAndBranchIfNonZero(temp1, slow_path->GetEntryLabel());
__ Bind(&do_put);
} else {
__ B(ne, slow_path->GetEntryLabel());
@@ -4556,6 +4603,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;
@@ -4585,11 +4658,11 @@
bool can_be_null) {
vixl32::Label is_null;
if (can_be_null) {
- __ Cbz(value, &is_null);
+ __ CompareAndBranchIfZero(value, &is_null);
}
GetAssembler()->LoadFromOffset(
kLoadWord, card, tr, Thread::CardTableOffset<kArmPointerSize>().Int32Value());
- __ Lsr(temp, object, gc::accounting::CardTable::kCardShift);
+ __ Lsr(temp, object, Operand::From(gc::accounting::CardTable::kCardShift));
__ Strb(card, MemOperand(card, temp));
if (can_be_null) {
__ Bind(&is_null);
@@ -4644,10 +4717,10 @@
GetAssembler()->LoadFromOffset(
kLoadUnsignedHalfword, temp, tr, Thread::ThreadFlagsOffset<kArmPointerSize>().Int32Value());
if (successor == nullptr) {
- __ Cbnz(temp, slow_path->GetEntryLabel());
+ __ CompareAndBranchIfNonZero(temp, slow_path->GetEntryLabel());
__ Bind(slow_path->GetReturnLabel());
} else {
- __ Cbz(temp, codegen_->GetLabelOf(successor));
+ __ CompareAndBranchIfZero(temp, codegen_->GetLabelOf(successor));
__ B(slow_path->GetEntryLabel());
}
}
@@ -4915,7 +4988,7 @@
void InstructionCodeGeneratorARMVIXL::VisitLoadClass(HLoadClass* cls) {
LocationSummary* locations = cls->GetLocations();
if (cls->NeedsAccessCheck()) {
- codegen_->MoveConstant(locations->GetTemp(0), cls->GetTypeIndex());
+ codegen_->MoveConstant(locations->GetTemp(0), cls->GetTypeIndex().index_);
codegen_->InvokeRuntime(kQuickInitializeTypeAndVerifyAccess, cls, cls->GetDexPc());
CheckEntrypointTypes<kQuickInitializeTypeAndVerifyAccess, void*, uint32_t>();
return;
@@ -4947,7 +5020,7 @@
ArtMethod::DexCacheResolvedTypesOffset(kArmPointerSize).Int32Value();
GetAssembler()->LoadFromOffset(kLoadWord, out, current_method, resolved_types_offset);
// /* GcRoot<mirror::Class> */ out = out[type_index]
- size_t offset = CodeGenerator::GetCacheOffset(cls->GetTypeIndex());
+ size_t offset = CodeGenerator::GetCacheOffset(cls->GetTypeIndex().index_);
GenerateGcRootFieldLoad(cls, out_loc, out, offset, kEmitCompilerReadBarrier);
generate_null_check = !cls->IsInDexCache();
break;
@@ -4962,7 +5035,7 @@
cls, cls, cls->GetDexPc(), cls->MustGenerateClinitCheck());
codegen_->AddSlowPath(slow_path);
if (generate_null_check) {
- __ Cbz(out, slow_path->GetEntryLabel());
+ __ CompareAndBranchIfZero(out, slow_path->GetEntryLabel());
}
if (cls->MustGenerateClinitCheck()) {
GenerateClassInitializationCheck(slow_path, out);
@@ -5153,14 +5226,17 @@
// Return 0 if `obj` is null.
// avoid null check if we know obj is not null.
if (instruction->MustDoNullCheck()) {
- __ Cbz(obj, &zero);
+ __ CompareAndBranchIfZero(obj, &zero, /* far_target */ false);
}
- // /* 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 +5246,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;
@@ -5177,7 +5259,7 @@
// /* HeapReference<Class> */ out = out->super_class_
GenerateReferenceLoadOneRegister(instruction, out_loc, super_offset, maybe_temp_loc);
// If `out` is null, we use it for the result, and jump to `done`.
- __ Cbz(out, &done);
+ __ CompareAndBranchIfZero(out, &done, /* far_target */ false);
__ Cmp(out, cls);
__ B(ne, &loop);
__ Mov(out, 1);
@@ -5188,6 +5270,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);
@@ -5195,7 +5283,7 @@
__ B(eq, &success);
// /* HeapReference<Class> */ out = out->super_class_
GenerateReferenceLoadOneRegister(instruction, out_loc, super_offset, maybe_temp_loc);
- __ Cbnz(out, &loop);
+ __ CompareAndBranchIfNonZero(out, &loop);
// If `out` is null, we use it for the result, and jump to `done`.
__ B(&done);
__ Bind(&success);
@@ -5207,6 +5295,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);
@@ -5215,10 +5309,10 @@
// /* HeapReference<Class> */ out = out->component_type_
GenerateReferenceLoadOneRegister(instruction, out_loc, component_offset, maybe_temp_loc);
// If `out` is null, we use it for the result, and jump to `done`.
- __ Cbz(out, &done);
+ __ CompareAndBranchIfZero(out, &done, /* far_target */ false);
GetAssembler()->LoadFromOffset(kLoadUnsignedHalfword, out, out, primitive_offset);
static_assert(Primitive::kPrimNot == 0, "Expected 0 for kPrimNot");
- __ Cbnz(out, &zero);
+ __ CompareAndBranchIfNonZero(out, &zero, /* far_target */ false);
__ Bind(&exact_check);
__ Mov(out, 1);
__ B(&done);
@@ -5226,6 +5320,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,
@@ -5348,7 +5448,7 @@
vixl32::Label done;
// Avoid null check if we know obj is not null.
if (instruction->MustDoNullCheck()) {
- __ Cbz(obj, &done);
+ __ CompareAndBranchIfZero(obj, &done, /* far_target */ false);
}
// /* HeapReference<Class> */ temp = obj->klass_
@@ -5374,7 +5474,7 @@
// If the class reference currently in `temp` is null, jump to the slow path to throw the
// exception.
- __ Cbz(temp, type_check_slow_path->GetEntryLabel());
+ __ CompareAndBranchIfZero(temp, type_check_slow_path->GetEntryLabel());
// Otherwise, compare the classes.
__ Cmp(temp, cls);
@@ -5394,7 +5494,7 @@
// If the class reference currently in `temp` is null, jump to the slow path to throw the
// exception.
- __ Cbz(temp, type_check_slow_path->GetEntryLabel());
+ __ CompareAndBranchIfZero(temp, type_check_slow_path->GetEntryLabel());
// Otherwise, jump to the beginning of the loop.
__ B(&loop);
break;
@@ -5409,12 +5509,12 @@
// /* HeapReference<Class> */ temp = temp->component_type_
GenerateReferenceLoadOneRegister(instruction, temp_loc, component_offset, maybe_temp2_loc);
// If the component type is null, jump to the slow path to throw the exception.
- __ Cbz(temp, type_check_slow_path->GetEntryLabel());
+ __ CompareAndBranchIfZero(temp, type_check_slow_path->GetEntryLabel());
// Otherwise,the object is indeed an array, jump to label `check_non_primitive_component_type`
// to further check that this component type is not a primitive type.
GetAssembler()->LoadFromOffset(kLoadUnsignedHalfword, temp, temp, primitive_offset);
static_assert(Primitive::kPrimNot == 0, "Expected 0 for art::Primitive::kPrimNot");
- __ Cbnz(temp, type_check_slow_path->GetEntryLabel());
+ __ CompareAndBranchIfNonZero(temp, type_check_slow_path->GetEntryLabel());
break;
}
@@ -5491,6 +5591,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 +6022,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 +6142,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..38c756f 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);
};
@@ -357,7 +369,7 @@
FOR_EACH_UNIMPLEMENTED_INSTRUCTION(DEFINE_UNIMPLEMENTED_INSTRUCTION_VISITOR)
ArmVIXLAssembler* GetAssembler() const { return assembler_; }
- vixl::aarch32::MacroAssembler* GetVIXLAssembler() { return GetAssembler()->GetVIXLAssembler(); }
+ ArmVIXLMacroAssembler* GetVIXLAssembler() { return GetAssembler()->GetVIXLAssembler(); }
private:
void VisitUnimplemementedInstruction(HInstruction* instruction) {
@@ -439,7 +451,8 @@
void GenerateTestAndBranch(HInstruction* instruction,
size_t condition_input_index,
vixl::aarch32::Label* true_target,
- vixl::aarch32::Label* false_target);
+ vixl::aarch32::Label* false_target,
+ bool far_target = true);
void GenerateCompareTestAndBranch(HCondition* condition,
vixl::aarch32::Label* true_target,
vixl::aarch32::Label* false_target);
@@ -492,7 +505,7 @@
const ArmVIXLAssembler& GetAssembler() const OVERRIDE { return assembler_; }
- vixl::aarch32::MacroAssembler* GetVIXLAssembler() { return GetAssembler()->GetVIXLAssembler(); }
+ ArmVIXLMacroAssembler* GetVIXLAssembler() { return GetAssembler()->GetVIXLAssembler(); }
size_t GetWordSize() const OVERRIDE { return kArmWordSize; }
@@ -513,7 +526,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_mips.cc b/compiler/optimizing/code_generator_mips.cc
index 573bb50..8f94834 100644
--- a/compiler/optimizing/code_generator_mips.cc
+++ b/compiler/optimizing/code_generator_mips.cc
@@ -224,7 +224,7 @@
SaveLiveRegisters(codegen, locations);
InvokeRuntimeCallingConvention calling_convention;
- __ LoadConst32(calling_convention.GetRegisterAt(0), cls_->GetTypeIndex());
+ __ LoadConst32(calling_convention.GetRegisterAt(0), cls_->GetTypeIndex().index_);
QuickEntrypointEnum entrypoint = do_clinit_ ? kQuickInitializeStaticStorage
: kQuickInitializeType;
@@ -1056,7 +1056,7 @@
uint32_t literal_offset = __ GetLabelLocation(literal->GetLabel());
linker_patches->push_back(LinkerPatch::TypePatch(literal_offset,
target_type.dex_file,
- target_type.type_index));
+ target_type.type_index.index_));
}
for (const auto& entry : boot_image_address_patches_) {
DCHECK(GetCompilerOptions().GetIncludePatchInformation());
@@ -1073,8 +1073,8 @@
}
CodeGeneratorMIPS::PcRelativePatchInfo* CodeGeneratorMIPS::NewPcRelativeTypePatch(
- const DexFile& dex_file, uint32_t type_index) {
- return NewPcRelativePatch(dex_file, type_index, &pc_relative_type_patches_);
+ const DexFile& dex_file, dex::TypeIndex type_index) {
+ return NewPcRelativePatch(dex_file, type_index.index_, &pc_relative_type_patches_);
}
CodeGeneratorMIPS::PcRelativePatchInfo* CodeGeneratorMIPS::NewPcRelativeDexCacheArrayPatch(
@@ -1117,7 +1117,7 @@
}
Literal* CodeGeneratorMIPS::DeduplicateBootImageTypeLiteral(const DexFile& dex_file,
- uint32_t type_index) {
+ dex::TypeIndex type_index) {
return boot_image_type_patches_.GetOrCreate(
TypeReference(&dex_file, type_index),
[this]() { return __ NewLiteral<uint32_t>(/* placeholder */ 0u); });
@@ -5207,6 +5207,11 @@
case HLoadString::LoadKind::kDexCacheViaMethod:
fallback_load = false;
break;
+ case HLoadString::LoadKind::kJitTableAddress:
+ DCHECK(Runtime::Current()->UseJitCompilation());
+ // TODO: implement.
+ fallback_load = true;
+ break;
}
if (fallback_load) {
desired_string_load_kind = HLoadString::LoadKind::kDexCacheViaMethod;
@@ -5534,7 +5539,7 @@
void InstructionCodeGeneratorMIPS::VisitLoadClass(HLoadClass* cls) {
LocationSummary* locations = cls->GetLocations();
if (cls->NeedsAccessCheck()) {
- codegen_->MoveConstant(locations->GetTemp(0), cls->GetTypeIndex());
+ codegen_->MoveConstant(locations->GetTemp(0), cls->GetTypeIndex().index_);
codegen_->InvokeRuntime(kQuickInitializeTypeAndVerifyAccess, cls, cls->GetDexPc());
CheckEntrypointTypes<kQuickInitializeTypeAndVerifyAccess, void*, uint32_t>();
return;
@@ -5628,7 +5633,7 @@
base_or_current_method_reg,
ArtMethod::DexCacheResolvedTypesOffset(kArmPointerSize).Int32Value());
// /* GcRoot<mirror::Class> */ out = out[type_index]
- size_t offset = CodeGenerator::GetCacheOffset(cls->GetTypeIndex());
+ size_t offset = CodeGenerator::GetCacheOffset(cls->GetTypeIndex().index_);
GenerateGcRootFieldLoad(cls, out_loc, out, offset);
generate_null_check = !cls->IsInDexCache();
}
@@ -5970,7 +5975,7 @@
Register current_method_register = calling_convention.GetRegisterAt(2);
__ Lw(current_method_register, SP, kCurrentMethodStackOffset);
// Move an uint16_t value to a register.
- __ LoadConst32(calling_convention.GetRegisterAt(0), instruction->GetTypeIndex());
+ __ LoadConst32(calling_convention.GetRegisterAt(0), instruction->GetTypeIndex().index_);
codegen_->InvokeRuntime(instruction->GetEntrypoint(), instruction, instruction->GetDexPc());
CheckEntrypointTypes<kQuickAllocArrayWithAccessCheck,
void*, uint32_t, int32_t, ArtMethod*>();
diff --git a/compiler/optimizing/code_generator_mips.h b/compiler/optimizing/code_generator_mips.h
index e132819..e225d20 100644
--- a/compiler/optimizing/code_generator_mips.h
+++ b/compiler/optimizing/code_generator_mips.h
@@ -449,11 +449,11 @@
};
PcRelativePatchInfo* NewPcRelativeStringPatch(const DexFile& dex_file, uint32_t string_index);
- PcRelativePatchInfo* NewPcRelativeTypePatch(const DexFile& dex_file, uint32_t type_index);
+ PcRelativePatchInfo* NewPcRelativeTypePatch(const DexFile& dex_file, dex::TypeIndex type_index);
PcRelativePatchInfo* NewPcRelativeDexCacheArrayPatch(const DexFile& dex_file,
uint32_t element_offset);
Literal* DeduplicateBootImageStringLiteral(const DexFile& dex_file, uint32_t string_index);
- Literal* DeduplicateBootImageTypeLiteral(const DexFile& dex_file, uint32_t type_index);
+ Literal* DeduplicateBootImageTypeLiteral(const DexFile& dex_file, dex::TypeIndex type_index);
Literal* DeduplicateBootImageAddressLiteral(uint32_t address);
void EmitPcRelativeAddressPlaceholder(PcRelativePatchInfo* info, Register out, Register base);
diff --git a/compiler/optimizing/code_generator_mips64.cc b/compiler/optimizing/code_generator_mips64.cc
index 1a54935..02b01c8 100644
--- a/compiler/optimizing/code_generator_mips64.cc
+++ b/compiler/optimizing/code_generator_mips64.cc
@@ -180,7 +180,7 @@
SaveLiveRegisters(codegen, locations);
InvokeRuntimeCallingConvention calling_convention;
- __ LoadConst32(calling_convention.GetRegisterAt(0), cls_->GetTypeIndex());
+ __ LoadConst32(calling_convention.GetRegisterAt(0), cls_->GetTypeIndex().index_);
QuickEntrypointEnum entrypoint = do_clinit_ ? kQuickInitializeStaticStorage
: kQuickInitializeType;
mips64_codegen->InvokeRuntime(entrypoint, at_, dex_pc_, this);
@@ -3157,7 +3157,7 @@
void InstructionCodeGeneratorMIPS64::VisitLoadClass(HLoadClass* cls) {
LocationSummary* locations = cls->GetLocations();
if (cls->NeedsAccessCheck()) {
- codegen_->MoveConstant(locations->GetTemp(0), cls->GetTypeIndex());
+ codegen_->MoveConstant(locations->GetTemp(0), cls->GetTypeIndex().index_);
codegen_->InvokeRuntime(kQuickInitializeTypeAndVerifyAccess, cls, cls->GetDexPc());
CheckEntrypointTypes<kQuickInitializeTypeAndVerifyAccess, void*, uint32_t>();
return;
@@ -3174,7 +3174,7 @@
__ LoadFromOffset(kLoadDoubleword, out, current_method,
ArtMethod::DexCacheResolvedTypesOffset(kMips64PointerSize).Int32Value());
__ LoadFromOffset(
- kLoadUnsignedWord, out, out, CodeGenerator::GetCacheOffset(cls->GetTypeIndex()));
+ kLoadUnsignedWord, out, out, CodeGenerator::GetCacheOffset(cls->GetTypeIndex().index_));
// TODO: We will need a read barrier here.
if (!cls->IsInDexCache() || cls->MustGenerateClinitCheck()) {
DCHECK(cls->CanCallRuntime());
@@ -3382,7 +3382,8 @@
void InstructionCodeGeneratorMIPS64::VisitNewArray(HNewArray* instruction) {
LocationSummary* locations = instruction->GetLocations();
// Move an uint16_t value to a register.
- __ LoadConst32(locations->GetTemp(0).AsRegister<GpuRegister>(), instruction->GetTypeIndex());
+ __ LoadConst32(locations->GetTemp(0).AsRegister<GpuRegister>(),
+ instruction->GetTypeIndex().index_);
codegen_->InvokeRuntime(instruction->GetEntrypoint(), instruction, instruction->GetDexPc());
CheckEntrypointTypes<kQuickAllocArrayWithAccessCheck, void*, uint32_t, int32_t, ArtMethod*>();
}
diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc
index 2451b8d..51e902a 100644
--- a/compiler/optimizing/code_generator_x86.cc
+++ b/compiler/optimizing/code_generator_x86.cc
@@ -265,7 +265,7 @@
SaveLiveRegisters(codegen, locations);
InvokeRuntimeCallingConvention calling_convention;
- __ movl(calling_convention.GetRegisterAt(0), Immediate(cls_->GetTypeIndex()));
+ __ movl(calling_convention.GetRegisterAt(0), Immediate(cls_->GetTypeIndex().index_));
x86_codegen->InvokeRuntime(do_clinit_ ? kQuickInitializeStaticStorage
: kQuickInitializeType,
at_, dex_pc_, this);
@@ -1012,6 +1012,7 @@
simple_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
string_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
type_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
+ jit_string_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
constant_area_start_(-1),
fixups_to_jump_tables_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
method_address_offset_(-1) {
@@ -4167,7 +4168,7 @@
void InstructionCodeGeneratorX86::VisitNewArray(HNewArray* instruction) {
InvokeRuntimeCallingConvention calling_convention;
- __ movl(calling_convention.GetRegisterAt(0), Immediate(instruction->GetTypeIndex()));
+ __ movl(calling_convention.GetRegisterAt(0), Immediate(instruction->GetTypeIndex().index_));
// Note: if heap poisoning is enabled, the entry point takes cares
// of poisoning the reference.
codegen_->InvokeRuntime(instruction->GetEntrypoint(), instruction, instruction->GetDexPc());
@@ -4611,7 +4612,7 @@
}
void CodeGeneratorX86::RecordTypePatch(HLoadClass* load_class) {
- type_patches_.emplace_back(load_class->GetDexFile(), load_class->GetTypeIndex());
+ type_patches_.emplace_back(load_class->GetDexFile(), load_class->GetTypeIndex().index_);
__ Bind(&type_patches_.back().label);
}
@@ -6059,7 +6060,7 @@
void InstructionCodeGeneratorX86::VisitLoadClass(HLoadClass* cls) {
LocationSummary* locations = cls->GetLocations();
if (cls->NeedsAccessCheck()) {
- codegen_->MoveConstant(locations->GetTemp(0), cls->GetTypeIndex());
+ codegen_->MoveConstant(locations->GetTemp(0), cls->GetTypeIndex().index_);
codegen_->InvokeRuntime(kQuickInitializeTypeAndVerifyAccess, cls, cls->GetDexPc());
CheckEntrypointTypes<kQuickInitializeTypeAndVerifyAccess, void*, uint32_t>();
return;
@@ -6141,7 +6142,8 @@
// /* GcRoot<mirror::Class> */ out = out[type_index]
GenerateGcRootFieldLoad(cls,
out_loc,
- Address(out, CodeGenerator::GetCacheOffset(cls->GetTypeIndex())),
+ Address(out,
+ CodeGenerator::GetCacheOffset(cls->GetTypeIndex().index_)),
/* fixup_label */ nullptr,
read_barrier_option);
generate_null_check = !cls->IsInDexCache();
@@ -6218,16 +6220,15 @@
break;
case HLoadString::LoadKind::kDexCacheViaMethod:
break;
+ case HLoadString::LoadKind::kJitTableAddress:
+ DCHECK(Runtime::Current()->UseJitCompilation());
+ break;
}
return desired_string_load_kind;
}
void LocationsBuilderX86::VisitLoadString(HLoadString* load) {
- LocationSummary::CallKind call_kind = (load->NeedsEnvironment() || kEmitCompilerReadBarrier)
- ? ((load->GetLoadKind() == HLoadString::LoadKind::kDexCacheViaMethod)
- ? LocationSummary::kCallOnMainOnly
- : LocationSummary::kCallOnSlowPath)
- : LocationSummary::kNoCall;
+ LocationSummary::CallKind call_kind = CodeGenerator::GetLoadStringCallKind(load);
LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(load, call_kind);
HLoadString::LoadKind load_kind = load->GetLoadKind();
if (load_kind == HLoadString::LoadKind::kBootImageLinkTimePcRelative ||
@@ -6252,6 +6253,14 @@
}
}
+Label* CodeGeneratorX86::NewJitRootStringPatch(const DexFile& dex_file, uint32_t dex_index) {
+ jit_string_roots_.Overwrite(StringReference(&dex_file, dex_index), /* placeholder */ 0u);
+ // Add a patch entry and return the label.
+ jit_string_patches_.emplace_back(dex_file, dex_index);
+ PatchInfo<Label>* info = &jit_string_patches_.back();
+ return &info->label;
+}
+
void InstructionCodeGeneratorX86::VisitLoadString(HLoadString* load) {
LocationSummary* locations = load->GetLocations();
Location out_loc = locations->Out();
@@ -6280,7 +6289,7 @@
Register method_address = locations->InAt(0).AsRegister<Register>();
Address address = Address(method_address, CodeGeneratorX86::kDummy32BitOffset);
Label* fixup_label = codegen_->NewStringBssEntryPatch(load);
- // /* GcRoot<mirror::Class> */ out = *address /* PC-relative */
+ // /* GcRoot<mirror::String> */ out = *address /* PC-relative */
GenerateGcRootFieldLoad(load, out_loc, address, fixup_label, kCompilerReadBarrierOption);
SlowPathCode* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathX86(load);
codegen_->AddSlowPath(slow_path);
@@ -6289,6 +6298,14 @@
__ Bind(slow_path->GetExitLabel());
return;
}
+ case HLoadString::LoadKind::kJitTableAddress: {
+ Address address = Address::Absolute(CodeGeneratorX86::kDummy32BitOffset);
+ Label* fixup_label = codegen_->NewJitRootStringPatch(
+ load->GetDexFile(), load->GetStringIndex());
+ // /* GcRoot<mirror::String> */ out = *address
+ GenerateGcRootFieldLoad(load, out_loc, address, fixup_label, kCompilerReadBarrierOption);
+ return;
+ }
default:
break;
}
@@ -6849,24 +6866,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;
}
}
@@ -7562,7 +7579,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);
@@ -7736,6 +7753,20 @@
}
}
+void CodeGeneratorX86::EmitJitRootPatches(uint8_t* code, const uint8_t* roots_data) {
+ for (const PatchInfo<Label>& info : jit_string_patches_) {
+ const auto& it = jit_string_roots_.find(StringReference(&info.dex_file, info.index));
+ DCHECK(it != jit_string_roots_.end());
+ size_t index_in_table = it->second;
+ uint32_t code_offset = info.label.Position() - kLabelPositionToLiteralOffsetAdjustment;
+ uintptr_t address =
+ reinterpret_cast<uintptr_t>(roots_data) + index_in_table * sizeof(GcRoot<mirror::Object>);
+ typedef __attribute__((__aligned__(1))) uint32_t unaligned_uint32_t;
+ reinterpret_cast<unaligned_uint32_t*>(code + code_offset)[0] =
+ dchecked_integral_cast<uint32_t>(address);
+ }
+}
+
#undef __
} // namespace x86
diff --git a/compiler/optimizing/code_generator_x86.h b/compiler/optimizing/code_generator_x86.h
index 164231b..16ea6b5 100644
--- a/compiler/optimizing/code_generator_x86.h
+++ b/compiler/optimizing/code_generator_x86.h
@@ -414,12 +414,15 @@
void RecordTypePatch(HLoadClass* load_class);
Label* NewStringBssEntryPatch(HLoadString* load_string);
Label* NewPcRelativeDexCacheArrayPatch(const DexFile& dex_file, uint32_t element_offset);
+ Label* NewJitRootStringPatch(const DexFile& dex_file, uint32_t dex_index);
void MoveFromReturnRegister(Location trg, Primitive::Type type) OVERRIDE;
// Emit linker patches.
void EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patches) OVERRIDE;
+ void EmitJitRootPatches(uint8_t* code, const uint8_t* roots_data) OVERRIDE;
+
// Emit a write barrier.
void MarkGCCard(Register temp,
Register card,
@@ -616,6 +619,9 @@
// Type patch locations.
ArenaDeque<PatchInfo<Label>> type_patches_;
+ // Patches for string root accesses in JIT compiled code.
+ ArenaDeque<PatchInfo<Label>> jit_string_patches_;
+
// Offset to the start of the constant area in the assembled code.
// Used for fixups to the constant area.
int32_t constant_area_start_;
diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc
index 2425a4c..3467313 100644
--- a/compiler/optimizing/code_generator_x86_64.cc
+++ b/compiler/optimizing/code_generator_x86_64.cc
@@ -246,7 +246,8 @@
SaveLiveRegisters(codegen, locations);
InvokeRuntimeCallingConvention calling_convention;
- __ movl(CpuRegister(calling_convention.GetRegisterAt(0)), Immediate(cls_->GetTypeIndex()));
+ __ movl(CpuRegister(calling_convention.GetRegisterAt(0)),
+ Immediate(cls_->GetTypeIndex().index_));
x86_64_codegen->InvokeRuntime(do_clinit_ ? kQuickInitializeStaticStorage : kQuickInitializeType,
at_,
dex_pc_,
@@ -1110,7 +1111,7 @@
}
void CodeGeneratorX86_64::RecordTypePatch(HLoadClass* load_class) {
- type_patches_.emplace_back(load_class->GetDexFile(), load_class->GetTypeIndex());
+ type_patches_.emplace_back(load_class->GetDexFile(), load_class->GetTypeIndex().index_);
__ Bind(&type_patches_.back().label);
}
@@ -1258,7 +1259,8 @@
simple_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
string_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
type_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
- fixups_to_jump_tables_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)) {
+ fixups_to_jump_tables_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
+ jit_string_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)) {
AddAllocatedRegister(Location::RegisterLocation(kFakeReturnRegister));
}
@@ -4097,7 +4099,7 @@
void InstructionCodeGeneratorX86_64::VisitNewArray(HNewArray* instruction) {
InvokeRuntimeCallingConvention calling_convention;
codegen_->Load64BitValue(CpuRegister(calling_convention.GetRegisterAt(0)),
- instruction->GetTypeIndex());
+ instruction->GetTypeIndex().index_);
// Note: if heap poisoning is enabled, the entry point takes cares
// of poisoning the reference.
codegen_->InvokeRuntime(instruction->GetEntrypoint(), instruction, instruction->GetDexPc());
@@ -5484,7 +5486,7 @@
void InstructionCodeGeneratorX86_64::VisitLoadClass(HLoadClass* cls) {
LocationSummary* locations = cls->GetLocations();
if (cls->NeedsAccessCheck()) {
- codegen_->MoveConstant(locations->GetTemp(0), cls->GetTypeIndex());
+ codegen_->MoveConstant(locations->GetTemp(0), cls->GetTypeIndex().index_);
codegen_->InvokeRuntime(kQuickInitializeTypeAndVerifyAccess, cls, cls->GetDexPc());
CheckEntrypointTypes<kQuickInitializeTypeAndVerifyAccess, void*, uint32_t>();
return;
@@ -5567,7 +5569,7 @@
GenerateGcRootFieldLoad(
cls,
out_loc,
- Address(out, CodeGenerator::GetCacheOffset(cls->GetTypeIndex())),
+ Address(out, CodeGenerator::GetCacheOffset(cls->GetTypeIndex().index_)),
/* fixup_label */ nullptr,
read_barrier_option);
generate_null_check = !cls->IsInDexCache();
@@ -5630,16 +5632,15 @@
break;
case HLoadString::LoadKind::kDexCacheViaMethod:
break;
+ case HLoadString::LoadKind::kJitTableAddress:
+ DCHECK(Runtime::Current()->UseJitCompilation());
+ break;
}
return desired_string_load_kind;
}
void LocationsBuilderX86_64::VisitLoadString(HLoadString* load) {
- LocationSummary::CallKind call_kind = load->NeedsEnvironment()
- ? ((load->GetLoadKind() == HLoadString::LoadKind::kDexCacheViaMethod)
- ? LocationSummary::kCallOnMainOnly
- : LocationSummary::kCallOnSlowPath)
- : LocationSummary::kNoCall;
+ LocationSummary::CallKind call_kind = CodeGenerator::GetLoadStringCallKind(load);
LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(load, call_kind);
if (load->GetLoadKind() == HLoadString::LoadKind::kDexCacheViaMethod) {
locations->SetOut(Location::RegisterLocation(RAX));
@@ -5659,6 +5660,14 @@
}
}
+Label* CodeGeneratorX86_64::NewJitRootStringPatch(const DexFile& dex_file, uint32_t dex_index) {
+ jit_string_roots_.Overwrite(StringReference(&dex_file, dex_index), /* placeholder */ 0u);
+ // Add a patch entry and return the label.
+ jit_string_patches_.emplace_back(dex_file, dex_index);
+ PatchInfo<Label>* info = &jit_string_patches_.back();
+ return &info->label;
+}
+
void InstructionCodeGeneratorX86_64::VisitLoadString(HLoadString* load) {
LocationSummary* locations = load->GetLocations();
Location out_loc = locations->Out();
@@ -5690,6 +5699,15 @@
__ Bind(slow_path->GetExitLabel());
return;
}
+ case HLoadString::LoadKind::kJitTableAddress: {
+ Address address = Address::Absolute(CodeGeneratorX86_64::kDummy32BitOffset,
+ /* no_rip */ true);
+ Label* fixup_label =
+ codegen_->NewJitRootStringPatch(load->GetDexFile(), load->GetStringIndex());
+ // /* GcRoot<mirror::String> */ out = *address
+ GenerateGcRootFieldLoad(load, out_loc, address, fixup_label, kCompilerReadBarrierOption);
+ return;
+ }
default:
break;
}
@@ -6259,23 +6277,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;
}
@@ -7090,6 +7109,20 @@
}
}
+void CodeGeneratorX86_64::EmitJitRootPatches(uint8_t* code, const uint8_t* roots_data) {
+ for (const PatchInfo<Label>& info : jit_string_patches_) {
+ const auto& it = jit_string_roots_.find(StringReference(&info.dex_file, info.index));
+ DCHECK(it != jit_string_roots_.end());
+ size_t index_in_table = it->second;
+ uint32_t code_offset = info.label.Position() - kLabelPositionToLiteralOffsetAdjustment;
+ uintptr_t address =
+ reinterpret_cast<uintptr_t>(roots_data) + index_in_table * sizeof(GcRoot<mirror::Object>);
+ typedef __attribute__((__aligned__(1))) uint32_t unaligned_uint32_t;
+ reinterpret_cast<unaligned_uint32_t*>(code + code_offset)[0] =
+ dchecked_integral_cast<uint32_t>(address);
+ }
+}
+
#undef __
} // namespace x86_64
diff --git a/compiler/optimizing/code_generator_x86_64.h b/compiler/optimizing/code_generator_x86_64.h
index e5a4152..0f70b15 100644
--- a/compiler/optimizing/code_generator_x86_64.h
+++ b/compiler/optimizing/code_generator_x86_64.h
@@ -412,11 +412,14 @@
void RecordTypePatch(HLoadClass* load_class);
Label* NewStringBssEntryPatch(HLoadString* load_string);
Label* NewPcRelativeDexCacheArrayPatch(const DexFile& dex_file, uint32_t element_offset);
+ Label* NewJitRootStringPatch(const DexFile& dex_file, uint32_t dex_index);
void MoveFromReturnRegister(Location trg, Primitive::Type type) OVERRIDE;
void EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patches) OVERRIDE;
+ void EmitJitRootPatches(uint8_t* code, const uint8_t* roots_data) OVERRIDE;
+
const X86_64InstructionSetFeatures& GetInstructionSetFeatures() const {
return isa_features_;
}
@@ -602,6 +605,9 @@
// Fixups for jump tables need to be handled specially.
ArenaVector<JumpTableRIPFixup*> fixups_to_jump_tables_;
+ // Patches for string literals in JIT compiled code.
+ ArenaDeque<PatchInfo<Label>> jit_string_patches_;
+
DISALLOW_COPY_AND_ASSIGN(CodeGeneratorX86_64);
};
diff --git a/compiler/optimizing/common_arm.h b/compiler/optimizing/common_arm.h
index 5129daf..d3623f1 100644
--- a/compiler/optimizing/common_arm.h
+++ b/compiler/optimizing/common_arm.h
@@ -139,9 +139,14 @@
HConstant* instr = location.GetConstant();
if (instr->IsIntConstant()) {
return instr->AsIntConstant()->GetValue();
- } else {
- DCHECK(instr->IsNullConstant()) << instr->DebugName();
+ } else if (instr->IsNullConstant()) {
return 0;
+ } else {
+ DCHECK(instr->IsLongConstant()) << instr->DebugName();
+ const int64_t ret = instr->AsLongConstant()->GetValue();
+ DCHECK_GE(ret, std::numeric_limits<int32_t>::min());
+ DCHECK_LE(ret, std::numeric_limits<int32_t>::max());
+ return ret;
}
}
@@ -161,7 +166,7 @@
if (location.IsRegister()) {
return vixl::aarch32::Operand(RegisterFrom(location, type));
} else {
- return vixl::aarch32::Operand(Int64ConstantFrom(location));
+ return vixl::aarch32::Operand(Int32ConstantFrom(location));
}
}
diff --git a/compiler/optimizing/constant_folding_test.cc b/compiler/optimizing/constant_folding_test.cc
index 5fac3ac..7ef28ed 100644
--- a/compiler/optimizing/constant_folding_test.cc
+++ b/compiler/optimizing/constant_folding_test.cc
@@ -756,7 +756,7 @@
// Make various unsigned comparisons with zero against a parameter.
HInstruction* parameter = new (&allocator_) HParameterValue(
- graph_->GetDexFile(), 0, 0, Primitive::kPrimInt, true);
+ graph_->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimInt, true);
entry_block->AddInstruction(parameter);
entry_block->AddInstruction(new (&allocator_) HGoto());
diff --git a/compiler/optimizing/escape.cc b/compiler/optimizing/escape.cc
new file mode 100644
index 0000000..c80e19e
--- /dev/null
+++ b/compiler/optimizing/escape.cc
@@ -0,0 +1,100 @@
+/*
+ * 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 "escape.h"
+
+#include "nodes.h"
+
+namespace art {
+
+void CalculateEscape(HInstruction* reference,
+ bool (*no_escape)(HInstruction*, HInstruction*),
+ /*out*/ bool* is_singleton,
+ /*out*/ bool* is_singleton_and_non_escaping) {
+ // For references not allocated in the method, don't assume anything.
+ if (!reference->IsNewInstance() && !reference->IsNewArray()) {
+ *is_singleton = false;
+ *is_singleton_and_non_escaping = false;
+ return;
+ }
+ // Assume the best until proven otherwise.
+ *is_singleton = true;
+ *is_singleton_and_non_escaping = true;
+ // Visit all uses to determine if this reference can escape into the heap,
+ // a method call, an alias, etc.
+ for (const HUseListNode<HInstruction*>& use : reference->GetUses()) {
+ HInstruction* user = use.GetUser();
+ if (no_escape != nullptr && (*no_escape)(reference, user)) {
+ // Client supplied analysis says there is no escape.
+ continue;
+ } else if (user->IsBoundType() || user->IsNullCheck()) {
+ // BoundType shouldn't normally be necessary for an allocation. Just be conservative
+ // for the uncommon cases. Similarly, null checks are eventually eliminated for explicit
+ // allocations, but if we see one before it is simplified, assume an alias.
+ *is_singleton = false;
+ *is_singleton_and_non_escaping = false;
+ return;
+ } else if (user->IsPhi() || user->IsSelect() || user->IsInvoke() ||
+ (user->IsInstanceFieldSet() && (reference == user->InputAt(1))) ||
+ (user->IsUnresolvedInstanceFieldSet() && (reference == user->InputAt(1))) ||
+ (user->IsStaticFieldSet() && (reference == user->InputAt(1))) ||
+ (user->IsUnresolvedStaticFieldSet() && (reference == user->InputAt(0))) ||
+ (user->IsArraySet() && (reference == user->InputAt(2)))) {
+ // The reference is merged to HPhi/HSelect, passed to a callee, or stored to heap.
+ // Hence, the reference is no longer the only name that can refer to its value.
+ *is_singleton = false;
+ *is_singleton_and_non_escaping = false;
+ return;
+ } else if ((user->IsUnresolvedInstanceFieldGet() && (reference == user->InputAt(0))) ||
+ (user->IsUnresolvedInstanceFieldSet() && (reference == user->InputAt(0)))) {
+ // The field is accessed in an unresolved way. We mark the object as a non-singleton.
+ // Note that we could optimize this case and still perform some optimizations until
+ // we hit the unresolved access, but the conservative assumption is the simplest.
+ *is_singleton = false;
+ *is_singleton_and_non_escaping = false;
+ return;
+ } else if (user->IsReturn()) {
+ *is_singleton_and_non_escaping = false;
+ }
+ }
+
+ // Need for further analysis?
+ if (!*is_singleton_and_non_escaping) {
+ return;
+ }
+
+ // Look at the environment uses and if it's for HDeoptimize, it's treated the
+ // same as a return which escapes at the end of executing the compiled code.
+ // Other environment uses are fine, as long as all client optimizations that
+ // rely on this informations are disabled for debuggable.
+ for (const HUseListNode<HEnvironment*>& use : reference->GetEnvUses()) {
+ HEnvironment* user = use.GetUser();
+ if (user->GetHolder()->IsDeoptimize()) {
+ *is_singleton_and_non_escaping = false;
+ break;
+ }
+ }
+}
+
+bool IsNonEscapingSingleton(HInstruction* reference,
+ bool (*no_escape)(HInstruction*, HInstruction*)) {
+ bool is_singleton = true;
+ bool is_singleton_and_non_escaping = true;
+ CalculateEscape(reference, no_escape, &is_singleton, &is_singleton_and_non_escaping);
+ return is_singleton_and_non_escaping;
+}
+
+} // namespace art
diff --git a/compiler/optimizing/escape.h b/compiler/optimizing/escape.h
new file mode 100644
index 0000000..6514843
--- /dev/null
+++ b/compiler/optimizing/escape.h
@@ -0,0 +1,59 @@
+/*
+ * 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_OPTIMIZING_ESCAPE_H_
+#define ART_COMPILER_OPTIMIZING_ESCAPE_H_
+
+namespace art {
+
+class HInstruction;
+
+/*
+ * Methods related to escape analysis, i.e. determining whether an object
+ * allocation is visible outside ('escapes') its immediate method context.
+ */
+
+/*
+ * Performs escape analysis on the given instruction, typically a reference to an
+ * allocation. The method assigns true to parameter 'is_singleton' if the reference
+ * is the only name that can refer to its value during the lifetime of the method,
+ * meaning that the reference is not aliased with something else, is not stored to
+ * heap memory, and not passed to another method. The method assigns true to parameter
+ * 'is_singleton_and_non_escaping' if the reference is a singleton and is not returned
+ * to the caller or used as an environment local of an HDeoptimize instruction.
+ *
+ * When set, the no_escape function is applied to any use of the allocation instruction
+ * prior to any built-in escape analysis. This allows clients to define better escape
+ * analysis in certain case-specific circumstances. If 'no_escape(reference, user)'
+ * returns true, the user is assumed *not* to cause any escape right away. The return
+ * value false means the client cannot provide a definite answer and built-in escape
+ * analysis is applied to the user instead.
+ */
+void CalculateEscape(HInstruction* reference,
+ bool (*no_escape)(HInstruction*, HInstruction*),
+ /*out*/ bool* is_singleton,
+ /*out*/ bool* is_singleton_and_non_escaping);
+
+/*
+ * Convenience method for testing singleton and non-escaping property at once.
+ * Callers should be aware that this method invokes the full analysis at each call.
+ */
+bool IsNonEscapingSingleton(HInstruction* reference,
+ bool (*no_escape)(HInstruction*, HInstruction*));
+
+} // namespace art
+
+#endif // ART_COMPILER_OPTIMIZING_ESCAPE_H_
diff --git a/compiler/optimizing/gvn_test.cc b/compiler/optimizing/gvn_test.cc
index 6abf00e..437d35c 100644
--- a/compiler/optimizing/gvn_test.cc
+++ b/compiler/optimizing/gvn_test.cc
@@ -35,7 +35,7 @@
graph->AddBlock(entry);
graph->SetEntryBlock(entry);
HInstruction* parameter = new (&allocator) HParameterValue(graph->GetDexFile(),
- 0,
+ dex::TypeIndex(0),
0,
Primitive::kPrimNot);
entry->AddInstruction(parameter);
@@ -120,7 +120,7 @@
graph->AddBlock(entry);
graph->SetEntryBlock(entry);
HInstruction* parameter = new (&allocator) HParameterValue(graph->GetDexFile(),
- 0,
+ dex::TypeIndex(0),
0,
Primitive::kPrimNot);
entry->AddInstruction(parameter);
@@ -204,7 +204,7 @@
graph->SetEntryBlock(entry);
HInstruction* parameter = new (&allocator) HParameterValue(graph->GetDexFile(),
- 0,
+ dex::TypeIndex(0),
0,
Primitive::kPrimNot);
entry->AddInstruction(parameter);
@@ -352,7 +352,7 @@
inner_loop_exit->AddSuccessor(outer_loop_header);
HInstruction* parameter = new (&allocator) HParameterValue(graph->GetDexFile(),
- 0,
+ dex::TypeIndex(0),
0,
Primitive::kPrimBoolean);
entry->AddInstruction(parameter);
diff --git a/compiler/optimizing/induction_var_analysis_test.cc b/compiler/optimizing/induction_var_analysis_test.cc
index 031f1d7..3425b88 100644
--- a/compiler/optimizing/induction_var_analysis_test.cc
+++ b/compiler/optimizing/induction_var_analysis_test.cc
@@ -80,7 +80,7 @@
// Provide entry and exit instructions.
parameter_ = new (&allocator_) HParameterValue(
- graph_->GetDexFile(), 0, 0, Primitive::kPrimNot, true);
+ graph_->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimNot, true);
entry_->AddInstruction(parameter_);
constant0_ = graph_->GetIntConstant(0);
constant1_ = graph_->GetIntConstant(1);
diff --git a/compiler/optimizing/induction_var_range_test.cc b/compiler/optimizing/induction_var_range_test.cc
index 8bbdd4a..4c99e3c 100644
--- a/compiler/optimizing/induction_var_range_test.cc
+++ b/compiler/optimizing/induction_var_range_test.cc
@@ -62,9 +62,15 @@
graph_->SetEntryBlock(entry_block_);
graph_->SetExitBlock(exit_block_);
// Two parameters.
- x_ = new (&allocator_) HParameterValue(graph_->GetDexFile(), 0, 0, Primitive::kPrimInt);
+ x_ = new (&allocator_) HParameterValue(graph_->GetDexFile(),
+ dex::TypeIndex(0),
+ 0,
+ Primitive::kPrimInt);
entry_block_->AddInstruction(x_);
- y_ = new (&allocator_) HParameterValue(graph_->GetDexFile(), 0, 0, Primitive::kPrimInt);
+ y_ = new (&allocator_) HParameterValue(graph_->GetDexFile(),
+ dex::TypeIndex(0),
+ 0,
+ Primitive::kPrimInt);
entry_block_->AddInstruction(y_);
// Set arbitrary range analysis hint while testing private methods.
SetHint(x_);
@@ -572,7 +578,8 @@
HInstruction* new_array = new (&allocator_)
HNewArray(x_,
graph_->GetCurrentMethod(),
- 0, Primitive::kPrimInt,
+ 0,
+ dex::TypeIndex(Primitive::kPrimInt),
graph_->GetDexFile(),
kQuickAllocArray);
entry_block_->AddInstruction(new_array);
diff --git a/compiler/optimizing/inliner.cc b/compiler/optimizing/inliner.cc
index 7fe54b9..16a465a 100644
--- a/compiler/optimizing/inliner.cc
+++ b/compiler/optimizing/inliner.cc
@@ -197,15 +197,15 @@
}
}
-static uint32_t FindClassIndexIn(mirror::Class* cls,
- const DexFile& dex_file,
- Handle<mirror::DexCache> dex_cache)
+static dex::TypeIndex FindClassIndexIn(mirror::Class* cls,
+ const DexFile& dex_file,
+ Handle<mirror::DexCache> dex_cache)
REQUIRES_SHARED(Locks::mutator_lock_) {
- uint32_t index = DexFile::kDexNoIndex;
+ dex::TypeIndex index;
if (cls->GetDexCache() == nullptr) {
DCHECK(cls->IsArrayClass()) << cls->PrettyClass();
index = cls->FindTypeIndexInOtherDexFile(dex_file);
- } else if (cls->GetDexTypeIndex() == DexFile::kDexNoIndex16) {
+ } else if (!cls->GetDexTypeIndex().IsValid()) {
DCHECK(cls->IsProxyClass()) << cls->PrettyClass();
// TODO: deal with proxy classes.
} else if (IsSameDexFile(cls->GetDexFile(), dex_file)) {
@@ -223,8 +223,8 @@
// We cannot guarantee the entry in the dex cache will resolve to the same class,
// as there may be different class loaders. So only return the index if it's
// the right class in the dex cache already.
- if (index != DexFile::kDexNoIndex && dex_cache->GetResolvedType(index) != cls) {
- index = DexFile::kDexNoIndex;
+ if (index.IsValid() && dex_cache->GetResolvedType(index) != cls) {
+ index = dex::TypeIndex::Invalid();
}
}
@@ -363,9 +363,9 @@
<< invoke_instruction->DebugName();
const DexFile& caller_dex_file = *caller_compilation_unit_.GetDexFile();
- uint32_t class_index = FindClassIndexIn(
+ dex::TypeIndex class_index = FindClassIndexIn(
ic.GetMonomorphicType(), caller_dex_file, caller_compilation_unit_.GetDexCache());
- if (class_index == DexFile::kDexNoIndex) {
+ if (!class_index.IsValid()) {
VLOG(compiler) << "Call to " << ArtMethod::PrettyMethod(resolved_method)
<< " from inline cache is not inlined because its class is not"
<< " accessible to the caller";
@@ -417,7 +417,7 @@
HInstruction* HInliner::AddTypeGuard(HInstruction* receiver,
HInstruction* cursor,
HBasicBlock* bb_cursor,
- uint32_t class_index,
+ dex::TypeIndex class_index,
bool is_referrer,
HInstruction* invoke_instruction,
bool with_deoptimization) {
@@ -489,10 +489,10 @@
HInstruction* cursor = invoke_instruction->GetPrevious();
HBasicBlock* bb_cursor = invoke_instruction->GetBlock();
- uint32_t class_index = FindClassIndexIn(
+ dex::TypeIndex class_index = FindClassIndexIn(
ic.GetTypeAt(i), caller_dex_file, caller_compilation_unit_.GetDexCache());
HInstruction* return_replacement = nullptr;
- if (class_index == DexFile::kDexNoIndex ||
+ if (!class_index.IsValid() ||
!TryBuildAndInline(invoke_instruction, method, &return_replacement)) {
all_targets_inlined = false;
} else {
diff --git a/compiler/optimizing/inliner.h b/compiler/optimizing/inliner.h
index a1dcd58..682393e 100644
--- a/compiler/optimizing/inliner.h
+++ b/compiler/optimizing/inliner.h
@@ -17,6 +17,7 @@
#ifndef ART_COMPILER_OPTIMIZING_INLINER_H_
#define ART_COMPILER_OPTIMIZING_INLINER_H_
+#include "dex_file_types.h"
#include "invoke_type.h"
#include "optimization.h"
@@ -150,7 +151,7 @@
HInstruction* AddTypeGuard(HInstruction* receiver,
HInstruction* cursor,
HBasicBlock* bb_cursor,
- uint32_t class_index,
+ dex::TypeIndex class_index,
bool is_referrer,
HInstruction* invoke_instruction,
bool with_deoptimization)
diff --git a/compiler/optimizing/instruction_builder.cc b/compiler/optimizing/instruction_builder.cc
index c8c4ca7..40de5ce 100644
--- a/compiler/optimizing/instruction_builder.cc
+++ b/compiler/optimizing/instruction_builder.cc
@@ -908,7 +908,7 @@
false /* is_unresolved */);
}
-bool HInstructionBuilder::BuildNewInstance(uint16_t type_index, uint32_t dex_pc) {
+bool HInstructionBuilder::BuildNewInstance(dex::TypeIndex type_index, uint32_t dex_pc) {
ScopedObjectAccess soa(Thread::Current());
StackHandleScope<1> hs(soa.Self());
Handle<mirror::DexCache> dex_cache = dex_compilation_unit_->GetDexCache();
@@ -1004,7 +1004,7 @@
Handle<mirror::Class> resolved_method_class(hs.NewHandle(resolved_method->GetDeclaringClass()));
// The index at which the method's class is stored in the DexCache's type array.
- uint32_t storage_index = DexFile::kDexNoIndex;
+ dex::TypeIndex storage_index;
bool is_outer_class = (resolved_method->GetDeclaringClass() == outer_class.Get());
if (is_outer_class) {
storage_index = outer_class->GetDexTypeIndex();
@@ -1021,7 +1021,7 @@
if (IsInitialized(resolved_method_class)) {
*clinit_check_requirement = HInvokeStaticOrDirect::ClinitCheckRequirement::kNone;
- } else if (storage_index != DexFile::kDexNoIndex) {
+ } else if (storage_index.IsValid()) {
*clinit_check_requirement = HInvokeStaticOrDirect::ClinitCheckRequirement::kExplicit;
HLoadClass* load_class = new (arena_) HLoadClass(
graph_->GetCurrentMethod(),
@@ -1297,7 +1297,7 @@
return GetClassFrom(compiler_driver_, *dex_compilation_unit_);
}
-bool HInstructionBuilder::IsOutermostCompilingClass(uint16_t type_index) const {
+bool HInstructionBuilder::IsOutermostCompilingClass(dex::TypeIndex type_index) const {
ScopedObjectAccess soa(Thread::Current());
StackHandleScope<3> hs(soa.Self());
Handle<mirror::DexCache> dex_cache = dex_compilation_unit_->GetDexCache();
@@ -1360,7 +1360,7 @@
Handle<mirror::Class> outer_class(hs.NewHandle(GetOutermostCompilingClass()));
// The index at which the field's class is stored in the DexCache's type array.
- uint32_t storage_index;
+ dex::TypeIndex storage_index;
bool is_outer_class = (outer_class.Get() == resolved_field->GetDeclaringClass());
if (is_outer_class) {
storage_index = outer_class->GetDexTypeIndex();
@@ -1497,7 +1497,7 @@
}
void HInstructionBuilder::BuildFilledNewArray(uint32_t dex_pc,
- uint32_t type_index,
+ dex::TypeIndex type_index,
uint32_t number_of_vreg_arguments,
bool is_range,
uint32_t* args,
@@ -1644,7 +1644,7 @@
void HInstructionBuilder::BuildTypeCheck(const Instruction& instruction,
uint8_t destination,
uint8_t reference,
- uint16_t type_index,
+ dex::TypeIndex type_index,
uint32_t dex_pc) {
ScopedObjectAccess soa(Thread::Current());
StackHandleScope<1> hs(soa.Self());
@@ -1684,14 +1684,14 @@
}
}
-bool HInstructionBuilder::NeedsAccessCheck(uint32_t type_index,
+bool HInstructionBuilder::NeedsAccessCheck(dex::TypeIndex type_index,
Handle<mirror::DexCache> dex_cache,
bool* finalizable) const {
return !compiler_driver_->CanAccessInstantiableTypeWithoutChecks(
dex_compilation_unit_->GetDexMethodIndex(), dex_cache, type_index, finalizable);
}
-bool HInstructionBuilder::NeedsAccessCheck(uint32_t type_index, bool* finalizable) const {
+bool HInstructionBuilder::NeedsAccessCheck(dex::TypeIndex type_index, bool* finalizable) const {
ScopedObjectAccess soa(Thread::Current());
Handle<mirror::DexCache> dex_cache = dex_compilation_unit_->GetDexCache();
return NeedsAccessCheck(type_index, dex_cache, finalizable);
@@ -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);
}
}
}
@@ -2446,7 +2449,7 @@
}
case Instruction::NEW_INSTANCE: {
- if (!BuildNewInstance(instruction.VRegB_21c(), dex_pc)) {
+ if (!BuildNewInstance(dex::TypeIndex(instruction.VRegB_21c()), dex_pc)) {
return false;
}
UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction());
@@ -2454,7 +2457,7 @@
}
case Instruction::NEW_ARRAY: {
- uint16_t type_index = instruction.VRegC_22c();
+ dex::TypeIndex type_index(instruction.VRegC_22c());
HInstruction* length = LoadLocal(instruction.VRegB_22c(), Primitive::kPrimInt);
bool finalizable;
QuickEntrypointEnum entrypoint = NeedsAccessCheck(type_index, &finalizable)
@@ -2472,7 +2475,7 @@
case Instruction::FILLED_NEW_ARRAY: {
uint32_t number_of_vreg_arguments = instruction.VRegA_35c();
- uint32_t type_index = instruction.VRegB_35c();
+ dex::TypeIndex type_index(instruction.VRegB_35c());
uint32_t args[5];
instruction.GetVarArgs(args);
BuildFilledNewArray(dex_pc, type_index, number_of_vreg_arguments, false, args, 0);
@@ -2481,7 +2484,7 @@
case Instruction::FILLED_NEW_ARRAY_RANGE: {
uint32_t number_of_vreg_arguments = instruction.VRegA_3rc();
- uint32_t type_index = instruction.VRegB_3rc();
+ dex::TypeIndex type_index(instruction.VRegB_3rc());
uint32_t register_index = instruction.VRegC_3rc();
BuildFilledNewArray(
dex_pc, type_index, number_of_vreg_arguments, true, nullptr, register_index);
@@ -2638,7 +2641,7 @@
}
case Instruction::CONST_CLASS: {
- uint16_t type_index = instruction.VRegB_21c();
+ dex::TypeIndex type_index(instruction.VRegB_21c());
// `CanAccessTypeWithoutChecks` will tell whether the method being
// built is trying to access its own class, so that the generated
// code can optimize for this case. However, the optimization does not
@@ -2679,14 +2682,14 @@
case Instruction::INSTANCE_OF: {
uint8_t destination = instruction.VRegA_22c();
uint8_t reference = instruction.VRegB_22c();
- uint16_t type_index = instruction.VRegC_22c();
+ dex::TypeIndex type_index(instruction.VRegC_22c());
BuildTypeCheck(instruction, destination, reference, type_index, dex_pc);
break;
}
case Instruction::CHECK_CAST: {
uint8_t reference = instruction.VRegA_21c();
- uint16_t type_index = instruction.VRegB_21c();
+ dex::TypeIndex type_index(instruction.VRegB_21c());
BuildTypeCheck(instruction, -1, reference, type_index, dex_pc);
break;
}
diff --git a/compiler/optimizing/instruction_builder.h b/compiler/optimizing/instruction_builder.h
index aa34ddd..f29e522 100644
--- a/compiler/optimizing/instruction_builder.h
+++ b/compiler/optimizing/instruction_builder.h
@@ -20,6 +20,7 @@
#include "base/arena_containers.h"
#include "base/arena_object.h"
#include "block_builder.h"
+#include "dex_file_types.h"
#include "driver/compiler_driver.h"
#include "driver/compiler_driver-inl.h"
#include "driver/dex_compilation_unit.h"
@@ -100,11 +101,11 @@
// Returns whether the current method needs access check for the type.
// Output parameter finalizable is set to whether the type is finalizable.
- bool NeedsAccessCheck(uint32_t type_index,
+ bool NeedsAccessCheck(dex::TypeIndex type_index,
Handle<mirror::DexCache> dex_cache,
/*out*/bool* finalizable) const
REQUIRES_SHARED(Locks::mutator_lock_);
- bool NeedsAccessCheck(uint32_t type_index, /*out*/bool* finalizable) const;
+ bool NeedsAccessCheck(dex::TypeIndex type_index, /*out*/bool* finalizable) const;
template<typename T>
void Unop_12x(const Instruction& instruction, Primitive::Type type, uint32_t dex_pc);
@@ -176,7 +177,7 @@
// Builds a new array node and the instructions that fill it.
void BuildFilledNewArray(uint32_t dex_pc,
- uint32_t type_index,
+ dex::TypeIndex type_index,
uint32_t number_of_vreg_arguments,
bool is_range,
uint32_t* args,
@@ -205,7 +206,7 @@
void BuildTypeCheck(const Instruction& instruction,
uint8_t destination,
uint8_t reference,
- uint16_t type_index,
+ dex::TypeIndex type_index,
uint32_t dex_pc);
// Builds an instruction sequence for a switch statement.
@@ -218,7 +219,7 @@
mirror::Class* GetCompilingClass() const;
// Returns whether `type_index` points to the outer-most compiling method's class.
- bool IsOutermostCompilingClass(uint16_t type_index) const;
+ bool IsOutermostCompilingClass(dex::TypeIndex type_index) const;
void PotentiallySimplifyFakeString(uint16_t original_dex_register,
uint32_t dex_pc,
@@ -258,7 +259,7 @@
REQUIRES_SHARED(Locks::mutator_lock_);
// Build a HNewInstance instruction.
- bool BuildNewInstance(uint16_t type_index, uint32_t dex_pc);
+ bool BuildNewInstance(dex::TypeIndex type_index, uint32_t dex_pc);
// Return whether the compiler can assume `cls` is initialized.
bool IsInitialized(Handle<mirror::Class> cls) const
diff --git a/compiler/optimizing/intrinsics_arm64.cc b/compiler/optimizing/intrinsics_arm64.cc
index 451abc5..17a97da 100644
--- a/compiler/optimizing/intrinsics_arm64.cc
+++ b/compiler/optimizing/intrinsics_arm64.cc
@@ -2165,11 +2165,11 @@
__ Cbz(dst, slow_path->GetEntryLabel());
if (!length.IsConstant()) {
- // If the length is negative, bail out.
- __ Tbnz(WRegisterFrom(length), kWRegSize - 1, slow_path->GetEntryLabel());
- // If the length > 32 then (currently) prefer libcore's native implementation.
+ // Merge the following two comparisons into one:
+ // If the length is negative, bail out (delegate to libcore's native implementation).
+ // If the length > 32 then (currently) prefer libcore's native implementation.
__ Cmp(WRegisterFrom(length), kSystemArrayCopyCharThreshold);
- __ B(slow_path->GetEntryLabel(), gt);
+ __ B(slow_path->GetEntryLabel(), hi);
} else {
// We have already checked in the LocationsBuilder for the constant case.
DCHECK_GE(length.GetConstant()->AsIntConstant()->GetValue(), 0);
@@ -2379,11 +2379,11 @@
if (!length.IsConstant() &&
!optimizations.GetCountIsSourceLength() &&
!optimizations.GetCountIsDestinationLength()) {
- // If the length is negative, bail out.
- __ Tbnz(WRegisterFrom(length), kWRegSize - 1, intrinsic_slow_path->GetEntryLabel());
- // If the length >= 128 then (currently) prefer native implementation.
+ // Merge the following two comparisons into one:
+ // If the length is negative, bail out (delegate to libcore's native implementation).
+ // If the length >= 128 then (currently) prefer native implementation.
__ Cmp(WRegisterFrom(length), kSystemArrayCopyThreshold);
- __ B(intrinsic_slow_path->GetEntryLabel(), ge);
+ __ B(intrinsic_slow_path->GetEntryLabel(), hs);
}
// Validity checks: source.
CheckSystemArrayCopyPosition(masm,
diff --git a/compiler/optimizing/intrinsics_arm_vixl.cc b/compiler/optimizing/intrinsics_arm_vixl.cc
index e4bef34..c8e3534 100644
--- a/compiler/optimizing/intrinsics_arm_vixl.cc
+++ b/compiler/optimizing/intrinsics_arm_vixl.cc
@@ -303,7 +303,7 @@
vixl32::Register in_reg_hi = HighRegisterFrom(in);
vixl32::Label end;
__ Clz(out, in_reg_hi);
- __ Cbnz(in_reg_hi, &end);
+ __ CompareAndBranchIfNonZero(in_reg_hi, &end, /* far_target */ false);
__ Clz(out, in_reg_lo);
__ Add(out, out, 32);
__ Bind(&end);
@@ -345,7 +345,7 @@
vixl32::Label end;
__ Rbit(out, in_reg_lo);
__ Clz(out, out);
- __ Cbnz(in_reg_lo, &end);
+ __ CompareAndBranchIfNonZero(in_reg_lo, &end, /* far_target */ false);
__ Rbit(out, in_reg_hi);
__ Clz(out, out);
__ Add(out, out, 32);
@@ -518,7 +518,7 @@
void IntrinsicCodeGeneratorARMVIXL::VisitMemoryPeekByte(HInvoke* invoke) {
ArmVIXLAssembler* assembler = GetAssembler();
// Ignore upper 4B of long address.
- __ Ldrsb(OutputRegister(invoke), LowRegisterFrom(invoke->GetLocations()->InAt(0)));
+ __ Ldrsb(OutputRegister(invoke), MemOperand(LowRegisterFrom(invoke->GetLocations()->InAt(0))));
}
void IntrinsicLocationsBuilderARMVIXL::VisitMemoryPeekIntNative(HInvoke* invoke) {
@@ -528,7 +528,7 @@
void IntrinsicCodeGeneratorARMVIXL::VisitMemoryPeekIntNative(HInvoke* invoke) {
ArmVIXLAssembler* assembler = GetAssembler();
// Ignore upper 4B of long address.
- __ Ldr(OutputRegister(invoke), LowRegisterFrom(invoke->GetLocations()->InAt(0)));
+ __ Ldr(OutputRegister(invoke), MemOperand(LowRegisterFrom(invoke->GetLocations()->InAt(0))));
}
void IntrinsicLocationsBuilderARMVIXL::VisitMemoryPeekLongNative(HInvoke* invoke) {
@@ -545,9 +545,9 @@
vixl32::Register hi = HighRegisterFrom(invoke->GetLocations()->Out());
if (addr.Is(lo)) {
__ Ldr(hi, MemOperand(addr, 4));
- __ Ldr(lo, addr);
+ __ Ldr(lo, MemOperand(addr));
} else {
- __ Ldr(lo, addr);
+ __ Ldr(lo, MemOperand(addr));
__ Ldr(hi, MemOperand(addr, 4));
}
}
@@ -559,7 +559,7 @@
void IntrinsicCodeGeneratorARMVIXL::VisitMemoryPeekShortNative(HInvoke* invoke) {
ArmVIXLAssembler* assembler = GetAssembler();
// Ignore upper 4B of long address.
- __ Ldrsh(OutputRegister(invoke), LowRegisterFrom(invoke->GetLocations()->InAt(0)));
+ __ Ldrsh(OutputRegister(invoke), MemOperand(LowRegisterFrom(invoke->GetLocations()->InAt(0))));
}
static void CreateIntIntToVoidLocations(ArenaAllocator* arena, HInvoke* invoke) {
@@ -576,7 +576,7 @@
void IntrinsicCodeGeneratorARMVIXL::VisitMemoryPokeByte(HInvoke* invoke) {
ArmVIXLAssembler* assembler = GetAssembler();
- __ Strb(InputRegisterAt(invoke, 1), LowRegisterFrom(invoke->GetLocations()->InAt(0)));
+ __ Strb(InputRegisterAt(invoke, 1), MemOperand(LowRegisterFrom(invoke->GetLocations()->InAt(0))));
}
void IntrinsicLocationsBuilderARMVIXL::VisitMemoryPokeIntNative(HInvoke* invoke) {
@@ -585,7 +585,7 @@
void IntrinsicCodeGeneratorARMVIXL::VisitMemoryPokeIntNative(HInvoke* invoke) {
ArmVIXLAssembler* assembler = GetAssembler();
- __ Str(InputRegisterAt(invoke, 1), LowRegisterFrom(invoke->GetLocations()->InAt(0)));
+ __ Str(InputRegisterAt(invoke, 1), MemOperand(LowRegisterFrom(invoke->GetLocations()->InAt(0))));
}
void IntrinsicLocationsBuilderARMVIXL::VisitMemoryPokeLongNative(HInvoke* invoke) {
@@ -598,7 +598,7 @@
vixl32::Register addr = LowRegisterFrom(invoke->GetLocations()->InAt(0));
// Worst case: Control register bit SCTLR.A = 0. Then unaligned accesses throw a processor
// exception. So we can't use ldrd as addr may be unaligned.
- __ Str(LowRegisterFrom(invoke->GetLocations()->InAt(1)), addr);
+ __ Str(LowRegisterFrom(invoke->GetLocations()->InAt(1)), MemOperand(addr));
__ Str(HighRegisterFrom(invoke->GetLocations()->InAt(1)), MemOperand(addr, 4));
}
@@ -608,7 +608,7 @@
void IntrinsicCodeGeneratorARMVIXL::VisitMemoryPokeShortNative(HInvoke* invoke) {
ArmVIXLAssembler* assembler = GetAssembler();
- __ Strh(InputRegisterAt(invoke, 1), LowRegisterFrom(invoke->GetLocations()->InAt(0)));
+ __ Strh(InputRegisterAt(invoke, 1), MemOperand(LowRegisterFrom(invoke->GetLocations()->InAt(0))));
}
void IntrinsicLocationsBuilderARMVIXL::VisitThreadCurrentThread(HInvoke* invoke) {
@@ -842,8 +842,8 @@
__ Add(temp_reg, base, offset);
vixl32::Label loop_head;
__ Bind(&loop_head);
- __ Ldrexd(temp_lo, temp_hi, temp_reg);
- __ Strexd(temp_lo, value_lo, value_hi, temp_reg);
+ __ Ldrexd(temp_lo, temp_hi, MemOperand(temp_reg));
+ __ Strexd(temp_lo, value_lo, value_hi, MemOperand(temp_reg));
__ Cmp(temp_lo, 0);
__ B(ne, &loop_head);
} else {
@@ -1042,7 +1042,7 @@
vixl32::Label loop_head;
__ Bind(&loop_head);
- __ Ldrex(tmp, tmp_ptr);
+ __ Ldrex(tmp, MemOperand(tmp_ptr));
__ Subs(tmp, tmp, expected);
@@ -1052,7 +1052,7 @@
CodeBufferCheckScope::kMaximumSize);
__ itt(eq);
- __ strex(eq, tmp, value, tmp_ptr);
+ __ strex(eq, tmp, value, MemOperand(tmp_ptr));
__ cmp(eq, tmp, 1);
}
@@ -1158,7 +1158,7 @@
if (can_slow_path) {
slow_path = new (GetAllocator()) IntrinsicSlowPathARMVIXL(invoke);
codegen_->AddSlowPath(slow_path);
- __ Cbz(arg, slow_path->GetEntryLabel());
+ __ CompareAndBranchIfZero(arg, slow_path->GetEntryLabel());
}
// Reference equality check, return 0 if same reference.
@@ -1191,7 +1191,9 @@
}
// Shorter string is empty?
- __ Cbz(temp0, &end);
+ // Note that mirror::kUseStringCompression==true introduces lots of instructions,
+ // which makes &end label far away from this branch and makes it not 'CBZ-encodable'.
+ __ CompareAndBranchIfZero(temp0, &end, mirror::kUseStringCompression);
if (mirror::kUseStringCompression) {
// Check if both strings using same compression style to use this comparison loop.
@@ -1218,7 +1220,7 @@
static_assert(IsAligned<8>(kObjectAlignment),
"String data must be 8-byte aligned for unrolled CompareTo loop.");
- const size_t char_size = Primitive::ComponentSize(Primitive::kPrimChar);
+ const unsigned char_size = Primitive::ComponentSize(Primitive::kPrimChar);
DCHECK_EQ(char_size, 2u);
UseScratchRegisterScope temps(assembler->GetVIXLAssembler());
@@ -1281,20 +1283,20 @@
// For compressed strings we need to clear 0x7 from temp1, for uncompressed we need to clear
// 0xf. We also need to prepare the character extraction mask `uncompressed ? 0xffffu : 0xffu`.
// The compression flag is now in the highest bit of temp3, so let's play some tricks.
- __ orr(temp3, temp3, 0xffu << 23); // uncompressed ? 0xff800000u : 0x7ff80000u
- __ bic(temp1, temp1, Operand(temp3, vixl32::LSR, 31 - 3)); // &= ~(uncompressed ? 0xfu : 0x7u)
+ __ Orr(temp3, temp3, 0xffu << 23); // uncompressed ? 0xff800000u : 0x7ff80000u
+ __ Bic(temp1, temp1, Operand(temp3, vixl32::LSR, 31 - 3)); // &= ~(uncompressed ? 0xfu : 0x7u)
__ Asr(temp3, temp3, 7u); // uncompressed ? 0xffff0000u : 0xff0000u.
__ Lsr(temp2, temp2, temp1); // Extract second character.
__ Lsr(temp3, temp3, 16u); // uncompressed ? 0xffffu : 0xffu
__ Lsr(out, temp_reg, temp1); // Extract first character.
- __ and_(temp2, temp2, temp3);
- __ and_(out, out, temp3);
+ __ And(temp2, temp2, temp3);
+ __ And(out, out, temp3);
} else {
- __ bic(temp1, temp1, 0xf);
+ __ Bic(temp1, temp1, 0xf);
__ Lsr(temp2, temp2, temp1);
__ Lsr(out, temp_reg, temp1);
- __ movt(temp2, 0);
- __ movt(out, 0);
+ __ Movt(temp2, 0);
+ __ Movt(out, 0);
}
__ Sub(out, out, temp2);
@@ -1313,10 +1315,10 @@
// need to treat as unsigned. Start by freeing the bit with an ADD and continue
// further down by a LSRS+SBC which will flip the meaning of the flag but allow
// `subs temp0, #2; bhi different_compression_loop` to serve as the loop condition.
- __ add(temp0, temp0, temp0); // Unlike LSL, this ADD is always 16-bit.
+ __ Add(temp0, temp0, temp0); // Unlike LSL, this ADD is always 16-bit.
// `temp1` will hold the compressed data pointer, `temp2` the uncompressed data pointer.
- __ mov(temp1, str);
- __ mov(temp2, arg);
+ __ Mov(temp1, str);
+ __ Mov(temp2, arg);
__ Lsrs(temp3, temp3, 1u); // Continue the move of the compression flag.
{
AssemblerAccurateScope aas(assembler->GetVIXLAssembler(),
@@ -1326,11 +1328,11 @@
__ mov(cs, temp1, arg); // Preserves flags.
__ mov(cs, temp2, str); // Preserves flags.
}
- __ sbc(temp0, temp0, 0); // Complete the move of the compression flag.
+ __ Sbc(temp0, temp0, 0); // Complete the move of the compression flag.
// Adjust temp1 and temp2 from string pointers to data pointers.
- __ add(temp1, temp1, value_offset);
- __ add(temp2, temp2, value_offset);
+ __ Add(temp1, temp1, value_offset);
+ __ Add(temp2, temp2, value_offset);
vixl32::Label different_compression_loop;
vixl32::Label different_compression_diff;
@@ -1340,7 +1342,7 @@
__ Bind(&different_compression_loop);
__ Ldrb(temp_reg, MemOperand(temp1, c_char_size, PostIndex));
__ Ldrh(temp3, MemOperand(temp2, char_size, PostIndex));
- __ cmp(temp_reg, temp3);
+ __ Cmp(temp_reg, temp3);
__ B(ne, &different_compression_diff);
__ Subs(temp0, temp0, 2);
__ B(hi, &different_compression_loop);
@@ -1414,7 +1416,7 @@
StringEqualsOptimizations optimizations(invoke);
if (!optimizations.GetArgumentNotNull()) {
// Check if input is null, return false if it is.
- __ Cbz(arg, &return_false);
+ __ CompareAndBranchIfZero(arg, &return_false, /* far_target */ false);
}
// Reference equality check, return true if same reference.
@@ -1442,7 +1444,7 @@
// Return true if both strings are empty. Even with string compression `count == 0` means empty.
static_assert(static_cast<uint32_t>(mirror::StringCompressionFlag::kCompressed) == 0u,
"Expecting 0=compressed, 1=uncompressed");
- __ Cbz(temp, &return_true);
+ __ CompareAndBranchIfZero(temp, &return_true, /* far_target */ false);
// Assertions that must hold in order to compare strings 4 bytes at a time.
DCHECK_ALIGNED(value_offset, 4);
@@ -1467,7 +1469,7 @@
__ Bind(&loop);
__ Ldr(out, MemOperand(str, temp1));
__ Ldr(temp2, MemOperand(arg, temp1));
- __ Add(temp1, temp1, sizeof(uint32_t));
+ __ Add(temp1, temp1, Operand::From(sizeof(uint32_t)));
__ Cmp(out, temp2);
__ B(ne, &return_false);
// With string compression, we have compared 4 bytes, otherwise 2 chars.
@@ -1718,7 +1720,7 @@
} else if (length_is_input_length) {
// The only way the copy can succeed is if pos is zero.
vixl32::Register pos_reg = RegisterFrom(pos);
- __ Cbnz(pos_reg, slow_path->GetEntryLabel());
+ __ CompareAndBranchIfNonZero(pos_reg, slow_path->GetEntryLabel());
} else {
// Check that pos >= 0.
vixl32::Register pos_reg = RegisterFrom(pos);
@@ -1815,12 +1817,12 @@
if (!optimizations.GetSourceIsNotNull()) {
// Bail out if the source is null.
- __ Cbz(src, intrinsic_slow_path->GetEntryLabel());
+ __ CompareAndBranchIfZero(src, intrinsic_slow_path->GetEntryLabel());
}
if (!optimizations.GetDestinationIsNotNull() && !optimizations.GetDestinationIsSource()) {
// Bail out if the destination is null.
- __ Cbz(dest, intrinsic_slow_path->GetEntryLabel());
+ __ CompareAndBranchIfZero(dest, intrinsic_slow_path->GetEntryLabel());
}
// If the length is negative, bail out.
@@ -1865,13 +1867,13 @@
// /* HeapReference<Class> */ temp1 = temp1->component_type_
codegen_->GenerateFieldLoadWithBakerReadBarrier(
invoke, temp1_loc, temp1, component_offset, temp2_loc, /* needs_null_check */ false);
- __ Cbz(temp1, intrinsic_slow_path->GetEntryLabel());
+ __ CompareAndBranchIfZero(temp1, intrinsic_slow_path->GetEntryLabel());
// If heap poisoning is enabled, `temp1` has been unpoisoned
// by the the previous call to GenerateFieldLoadWithBakerReadBarrier.
// /* uint16_t */ temp1 = static_cast<uint16>(temp1->primitive_type_);
__ Ldrh(temp1, MemOperand(temp1, primitive_offset));
static_assert(Primitive::kPrimNot == 0, "Expected 0 for kPrimNot");
- __ Cbnz(temp1, intrinsic_slow_path->GetEntryLabel());
+ __ CompareAndBranchIfNonZero(temp1, intrinsic_slow_path->GetEntryLabel());
}
// /* HeapReference<Class> */ temp1 = dest->klass_
@@ -1889,13 +1891,13 @@
// /* HeapReference<Class> */ temp2 = temp1->component_type_
codegen_->GenerateFieldLoadWithBakerReadBarrier(
invoke, temp2_loc, temp1, component_offset, temp3_loc, /* needs_null_check */ false);
- __ Cbz(temp2, intrinsic_slow_path->GetEntryLabel());
+ __ CompareAndBranchIfZero(temp2, intrinsic_slow_path->GetEntryLabel());
// If heap poisoning is enabled, `temp2` has been unpoisoned
// by the the previous call to GenerateFieldLoadWithBakerReadBarrier.
// /* uint16_t */ temp2 = static_cast<uint16>(temp2->primitive_type_);
__ Ldrh(temp2, MemOperand(temp2, primitive_offset));
static_assert(Primitive::kPrimNot == 0, "Expected 0 for kPrimNot");
- __ Cbnz(temp2, intrinsic_slow_path->GetEntryLabel());
+ __ CompareAndBranchIfNonZero(temp2, intrinsic_slow_path->GetEntryLabel());
}
// For the same reason given earlier, `temp1` is not trashed by the
@@ -1918,7 +1920,7 @@
// comparison with null below, and this reference is not
// kept afterwards.
__ Ldr(temp1, MemOperand(temp1, super_offset));
- __ Cbnz(temp1, intrinsic_slow_path->GetEntryLabel());
+ __ CompareAndBranchIfNonZero(temp1, intrinsic_slow_path->GetEntryLabel());
__ Bind(&do_copy);
} else {
__ B(ne, intrinsic_slow_path->GetEntryLabel());
@@ -1944,24 +1946,24 @@
// Bail out if the destination is not a non primitive array.
// /* HeapReference<Class> */ temp3 = temp1->component_type_
__ Ldr(temp3, MemOperand(temp1, component_offset));
- __ Cbz(temp3, intrinsic_slow_path->GetEntryLabel());
+ __ CompareAndBranchIfZero(temp3, intrinsic_slow_path->GetEntryLabel());
assembler->MaybeUnpoisonHeapReference(temp3);
// /* uint16_t */ temp3 = static_cast<uint16>(temp3->primitive_type_);
__ Ldrh(temp3, MemOperand(temp3, primitive_offset));
static_assert(Primitive::kPrimNot == 0, "Expected 0 for kPrimNot");
- __ Cbnz(temp3, intrinsic_slow_path->GetEntryLabel());
+ __ CompareAndBranchIfNonZero(temp3, intrinsic_slow_path->GetEntryLabel());
}
if (!optimizations.GetSourceIsNonPrimitiveArray()) {
// Bail out if the source is not a non primitive array.
// /* HeapReference<Class> */ temp3 = temp2->component_type_
__ Ldr(temp3, MemOperand(temp2, component_offset));
- __ Cbz(temp3, intrinsic_slow_path->GetEntryLabel());
+ __ CompareAndBranchIfZero(temp3, intrinsic_slow_path->GetEntryLabel());
assembler->MaybeUnpoisonHeapReference(temp3);
// /* uint16_t */ temp3 = static_cast<uint16>(temp3->primitive_type_);
__ Ldrh(temp3, MemOperand(temp3, primitive_offset));
static_assert(Primitive::kPrimNot == 0, "Expected 0 for kPrimNot");
- __ Cbnz(temp3, intrinsic_slow_path->GetEntryLabel());
+ __ CompareAndBranchIfNonZero(temp3, intrinsic_slow_path->GetEntryLabel());
}
__ Cmp(temp1, temp2);
@@ -1978,7 +1980,7 @@
// /* HeapReference<Class> */ temp1 = temp1->super_class_
__ Ldr(temp1, MemOperand(temp1, super_offset));
// No need to unpoison the result, we're comparing against null.
- __ Cbnz(temp1, intrinsic_slow_path->GetEntryLabel());
+ __ CompareAndBranchIfNonZero(temp1, intrinsic_slow_path->GetEntryLabel());
__ Bind(&do_copy);
} else {
__ B(ne, intrinsic_slow_path->GetEntryLabel());
@@ -1994,7 +1996,7 @@
// /* HeapReference<Class> */ temp3 = temp1->component_type_
codegen_->GenerateFieldLoadWithBakerReadBarrier(
invoke, temp3_loc, temp1, component_offset, temp2_loc, /* needs_null_check */ false);
- __ Cbz(temp3, intrinsic_slow_path->GetEntryLabel());
+ __ CompareAndBranchIfZero(temp3, intrinsic_slow_path->GetEntryLabel());
// If heap poisoning is enabled, `temp3` has been unpoisoned
// by the the previous call to GenerateFieldLoadWithBakerReadBarrier.
} else {
@@ -2003,13 +2005,13 @@
assembler->MaybeUnpoisonHeapReference(temp1);
// /* HeapReference<Class> */ temp3 = temp1->component_type_
__ Ldr(temp3, MemOperand(temp1, component_offset));
- __ Cbz(temp3, intrinsic_slow_path->GetEntryLabel());
+ __ CompareAndBranchIfZero(temp3, intrinsic_slow_path->GetEntryLabel());
assembler->MaybeUnpoisonHeapReference(temp3);
}
// /* uint16_t */ temp3 = static_cast<uint16>(temp3->primitive_type_);
__ Ldrh(temp3, MemOperand(temp3, primitive_offset));
static_assert(Primitive::kPrimNot == 0, "Expected 0 for kPrimNot");
- __ Cbnz(temp3, intrinsic_slow_path->GetEntryLabel());
+ __ CompareAndBranchIfNonZero(temp3, intrinsic_slow_path->GetEntryLabel());
}
int32_t element_size = Primitive::ComponentSize(Primitive::kPrimNot);
diff --git a/compiler/optimizing/licm_test.cc b/compiler/optimizing/licm_test.cc
index 2a62643..8c34dc6 100644
--- a/compiler/optimizing/licm_test.cc
+++ b/compiler/optimizing/licm_test.cc
@@ -63,7 +63,10 @@
return_->AddSuccessor(exit_);
// Provide boiler-plate instructions.
- parameter_ = new (&allocator_) HParameterValue(graph_->GetDexFile(), 0, 0, Primitive::kPrimNot);
+ parameter_ = new (&allocator_) HParameterValue(graph_->GetDexFile(),
+ dex::TypeIndex(0),
+ 0,
+ Primitive::kPrimNot);
entry_->AddInstruction(parameter_);
int_constant_ = graph_->GetIntConstant(42);
float_constant_ = graph_->GetFloatConstant(42.0f);
diff --git a/compiler/optimizing/load_store_elimination.cc b/compiler/optimizing/load_store_elimination.cc
index 15e6059..edecf17 100644
--- a/compiler/optimizing/load_store_elimination.cc
+++ b/compiler/optimizing/load_store_elimination.cc
@@ -15,6 +15,8 @@
*/
#include "load_store_elimination.h"
+
+#include "escape.h"
#include "side_effects_analysis.h"
#include <iostream>
@@ -31,70 +33,12 @@
// whether it's a singleton, returned, etc.
class ReferenceInfo : public ArenaObject<kArenaAllocMisc> {
public:
- ReferenceInfo(HInstruction* reference, size_t pos) : reference_(reference), position_(pos) {
- is_singleton_ = true;
- is_singleton_and_non_escaping_ = true;
- if (!reference_->IsNewInstance() && !reference_->IsNewArray()) {
- // For references not allocated in the method, don't assume anything.
- is_singleton_ = false;
- is_singleton_and_non_escaping_ = false;
- return;
- }
-
- // Visit all uses to determine if this reference can spread into the heap,
- // a method call, etc.
- for (const HUseListNode<HInstruction*>& use : reference_->GetUses()) {
- HInstruction* user = use.GetUser();
- DCHECK(!user->IsNullCheck()) << "NullCheck should have been eliminated";
- if (user->IsBoundType()) {
- // BoundType shouldn't normally be necessary for a NewInstance.
- // Just be conservative for the uncommon cases.
- is_singleton_ = false;
- is_singleton_and_non_escaping_ = false;
- return;
- }
- if (user->IsPhi() || user->IsSelect() || user->IsInvoke() ||
- (user->IsInstanceFieldSet() && (reference_ == user->InputAt(1))) ||
- (user->IsUnresolvedInstanceFieldSet() && (reference_ == user->InputAt(1))) ||
- (user->IsStaticFieldSet() && (reference_ == user->InputAt(1))) ||
- (user->IsUnresolvedStaticFieldSet() && (reference_ == user->InputAt(0))) ||
- (user->IsArraySet() && (reference_ == user->InputAt(2)))) {
- // reference_ is merged to HPhi/HSelect, passed to a callee, or stored to heap.
- // reference_ isn't the only name that can refer to its value anymore.
- is_singleton_ = false;
- is_singleton_and_non_escaping_ = false;
- return;
- }
- if ((user->IsUnresolvedInstanceFieldGet() && (reference_ == user->InputAt(0))) ||
- (user->IsUnresolvedInstanceFieldSet() && (reference_ == user->InputAt(0)))) {
- // The field is accessed in an unresolved way. We mark the object as a non-singleton
- // to disable load/store optimizations on it.
- // Note that we could optimize this case and still perform some optimizations until
- // we hit the unresolved access, but disabling is the simplest.
- is_singleton_ = false;
- is_singleton_and_non_escaping_ = false;
- return;
- }
- if (user->IsReturn()) {
- is_singleton_and_non_escaping_ = false;
- }
- }
-
- if (!is_singleton_ || !is_singleton_and_non_escaping_) {
- return;
- }
-
- // Look at Environment uses and if it's for HDeoptimize, it's treated the same
- // as a return which escapes at the end of executing the compiled code. We don't
- // do store elimination for singletons that escape through HDeoptimize.
- // Other Environment uses are fine since LSE is disabled for debuggable.
- for (const HUseListNode<HEnvironment*>& use : reference_->GetEnvUses()) {
- HEnvironment* user = use.GetUser();
- if (user->GetHolder()->IsDeoptimize()) {
- is_singleton_and_non_escaping_ = false;
- break;
- }
- }
+ ReferenceInfo(HInstruction* reference, size_t pos)
+ : reference_(reference),
+ position_(pos),
+ is_singleton_(true),
+ is_singleton_and_non_escaping_(true) {
+ CalculateEscape(reference_, nullptr, &is_singleton_, &is_singleton_and_non_escaping_);
}
HInstruction* GetReference() const {
diff --git a/compiler/optimizing/loop_optimization_test.cc b/compiler/optimizing/loop_optimization_test.cc
index 7805a69..9a6b493 100644
--- a/compiler/optimizing/loop_optimization_test.cc
+++ b/compiler/optimizing/loop_optimization_test.cc
@@ -48,7 +48,10 @@
graph_->AddBlock(exit_block_);
graph_->SetEntryBlock(entry_block_);
graph_->SetExitBlock(exit_block_);
- parameter_ = new (&allocator_) HParameterValue(graph_->GetDexFile(), 0, 0, Primitive::kPrimInt);
+ parameter_ = new (&allocator_) HParameterValue(graph_->GetDexFile(),
+ dex::TypeIndex(0),
+ 0,
+ Primitive::kPrimInt);
entry_block_->AddInstruction(parameter_);
return_block_->AddInstruction(new (&allocator_) HReturnVoid());
exit_block_->AddInstruction(new (&allocator_) HExit());
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index e0c582a..eebc49c 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -29,6 +29,7 @@
#include "base/stl_util.h"
#include "base/transform_array_ref.h"
#include "dex_file.h"
+#include "dex_file_types.h"
#include "entrypoints/quick/quick_entrypoints_enum.h"
#include "handle.h"
#include "handle_scope.h"
@@ -800,7 +801,7 @@
}
// Catch block information constructor.
- TryCatchInformation(uint16_t catch_type_index, const DexFile& dex_file)
+ TryCatchInformation(dex::TypeIndex catch_type_index, const DexFile& dex_file)
: try_entry_(nullptr),
catch_dex_file_(&dex_file),
catch_type_index_(catch_type_index) {}
@@ -816,10 +817,10 @@
bool IsCatchAllTypeIndex() const {
DCHECK(IsCatchBlock());
- return catch_type_index_ == DexFile::kDexNoIndex16;
+ return !catch_type_index_.IsValid();
}
- uint16_t GetCatchTypeIndex() const {
+ dex::TypeIndex GetCatchTypeIndex() const {
DCHECK(IsCatchBlock());
return catch_type_index_;
}
@@ -836,7 +837,7 @@
// Exception type information. Only set for catch blocks.
const DexFile* catch_dex_file_;
- const uint16_t catch_type_index_;
+ const dex::TypeIndex catch_type_index_;
};
static constexpr size_t kNoLifetime = -1;
@@ -3671,7 +3672,7 @@
HNewInstance(HInstruction* cls,
HCurrentMethod* current_method,
uint32_t dex_pc,
- uint16_t type_index,
+ dex::TypeIndex type_index,
const DexFile& dex_file,
bool needs_access_check,
bool finalizable,
@@ -3686,7 +3687,7 @@
SetRawInputAt(1, current_method);
}
- uint16_t GetTypeIndex() const { return type_index_; }
+ dex::TypeIndex GetTypeIndex() const { return type_index_; }
const DexFile& GetDexFile() const { return dex_file_; }
// Calls runtime so needs an environment.
@@ -3719,7 +3720,7 @@
static_assert(kNumberOfNewInstancePackedBits <= kMaxNumberOfPackedBits,
"Too many packed fields.");
- const uint16_t type_index_;
+ const dex::TypeIndex type_index_;
const DexFile& dex_file_;
QuickEntrypointEnum entrypoint_;
@@ -4265,7 +4266,7 @@
HNewArray(HInstruction* length,
HCurrentMethod* current_method,
uint32_t dex_pc,
- uint16_t type_index,
+ dex::TypeIndex type_index,
const DexFile& dex_file,
QuickEntrypointEnum entrypoint)
: HExpression(Primitive::kPrimNot, SideEffects::CanTriggerGC(), dex_pc),
@@ -4276,7 +4277,7 @@
SetRawInputAt(1, current_method);
}
- uint16_t GetTypeIndex() const { return type_index_; }
+ dex::TypeIndex GetTypeIndex() const { return type_index_; }
const DexFile& GetDexFile() const { return dex_file_; }
// Calls runtime so needs an environment.
@@ -4292,7 +4293,7 @@
DECLARE_INSTRUCTION(NewArray);
private:
- const uint16_t type_index_;
+ const dex::TypeIndex type_index_;
const DexFile& dex_file_;
const QuickEntrypointEnum entrypoint_;
@@ -4829,7 +4830,7 @@
class HParameterValue FINAL : public HExpression<0> {
public:
HParameterValue(const DexFile& dex_file,
- uint16_t type_index,
+ dex::TypeIndex type_index,
uint8_t index,
Primitive::Type parameter_type,
bool is_this = false)
@@ -4842,7 +4843,7 @@
}
const DexFile& GetDexFile() const { return dex_file_; }
- uint16_t GetTypeIndex() const { return type_index_; }
+ dex::TypeIndex GetTypeIndex() const { return type_index_; }
uint8_t GetIndex() const { return index_; }
bool IsThis() const { return GetPackedFlag<kFlagIsThis>(); }
@@ -4860,7 +4861,7 @@
"Too many packed fields.");
const DexFile& dex_file_;
- const uint16_t type_index_;
+ const dex::TypeIndex type_index_;
// The index of this parameter in the parameters list. Must be less
// than HGraph::number_of_in_vregs_.
const uint8_t index_;
@@ -5455,7 +5456,7 @@
};
HLoadClass(HCurrentMethod* current_method,
- uint16_t type_index,
+ dex::TypeIndex type_index,
const DexFile& dex_file,
bool is_referrers_class,
uint32_t dex_pc,
@@ -5487,7 +5488,7 @@
void SetLoadKindWithTypeReference(LoadKind load_kind,
const DexFile& dex_file,
- uint32_t type_index) {
+ dex::TypeIndex type_index) {
DCHECK(HasTypeReference(load_kind));
DCHECK(IsSameDexFile(dex_file_, dex_file));
DCHECK_EQ(type_index_, type_index);
@@ -5511,7 +5512,7 @@
bool InstructionDataEquals(const HInstruction* other) const;
- size_t ComputeHashCode() const OVERRIDE { return type_index_; }
+ size_t ComputeHashCode() const OVERRIDE { return type_index_.index_; }
bool CanBeNull() const OVERRIDE { return false; }
@@ -5547,7 +5548,7 @@
loaded_class_rti_ = rti;
}
- uint32_t GetTypeIndex() const { return type_index_; }
+ dex::TypeIndex GetTypeIndex() const { return type_index_; }
const DexFile& GetDexFile() const { return dex_file_; }
uint32_t GetDexCacheElementOffset() const;
@@ -5630,7 +5631,7 @@
// for PC-relative loads, i.e. kDexCachePcRelative or kBootImageLinkTimePcRelative.
HUserRecord<HInstruction*> special_input_;
- const uint16_t type_index_;
+ const dex::TypeIndex type_index_;
const DexFile& dex_file_;
union {
@@ -5690,7 +5691,10 @@
// all other types are unavailable.
kDexCacheViaMethod,
- kLast = kDexCacheViaMethod
+ // Load from the root table associated with the JIT compiled method.
+ kJitTableAddress,
+
+ kLast = kJitTableAddress,
};
HLoadString(HCurrentMethod* current_method,
@@ -5748,7 +5752,8 @@
LoadKind load_kind = GetLoadKind();
if (load_kind == LoadKind::kBootImageLinkTimeAddress ||
load_kind == LoadKind::kBootImageLinkTimePcRelative ||
- load_kind == LoadKind::kBootImageAddress) {
+ load_kind == LoadKind::kBootImageAddress ||
+ load_kind == LoadKind::kJitTableAddress) {
return false;
}
return !IsInDexCache();
@@ -5801,7 +5806,8 @@
return load_kind == LoadKind::kBootImageLinkTimeAddress ||
load_kind == LoadKind::kBootImageLinkTimePcRelative ||
load_kind == LoadKind::kBssEntry ||
- load_kind == LoadKind::kDexCacheViaMethod;
+ load_kind == LoadKind::kDexCacheViaMethod ||
+ load_kind == LoadKind::kJitTableAddress;
}
static bool HasAddress(LoadKind load_kind) {
diff --git a/compiler/optimizing/nodes_test.cc b/compiler/optimizing/nodes_test.cc
index d4e2a58..5d9a652 100644
--- a/compiler/optimizing/nodes_test.cc
+++ b/compiler/optimizing/nodes_test.cc
@@ -35,7 +35,7 @@
graph->AddBlock(entry);
graph->SetEntryBlock(entry);
HInstruction* parameter = new (&allocator) HParameterValue(
- graph->GetDexFile(), 0, 0, Primitive::kPrimNot);
+ graph->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimNot);
entry->AddInstruction(parameter);
entry->AddInstruction(new (&allocator) HGoto());
@@ -78,9 +78,9 @@
graph->AddBlock(entry);
graph->SetEntryBlock(entry);
HInstruction* parameter1 = new (&allocator) HParameterValue(
- graph->GetDexFile(), 0, 0, Primitive::kPrimNot);
+ graph->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimNot);
HInstruction* parameter2 = new (&allocator) HParameterValue(
- graph->GetDexFile(), 0, 0, Primitive::kPrimNot);
+ graph->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimNot);
entry->AddInstruction(parameter1);
entry->AddInstruction(parameter2);
entry->AddInstruction(new (&allocator) HExit());
@@ -106,7 +106,7 @@
graph->AddBlock(entry);
graph->SetEntryBlock(entry);
HInstruction* parameter = new (&allocator) HParameterValue(
- graph->GetDexFile(), 0, 0, Primitive::kPrimNot);
+ graph->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimNot);
entry->AddInstruction(parameter);
ASSERT_FALSE(parameter->HasUses());
@@ -127,7 +127,7 @@
graph->AddBlock(entry);
graph->SetEntryBlock(entry);
HInstruction* parameter1 = new (&allocator) HParameterValue(
- graph->GetDexFile(), 0, 0, Primitive::kPrimNot);
+ graph->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimNot);
HInstruction* with_environment = new (&allocator) HNullCheck(parameter1, 0);
entry->AddInstruction(parameter1);
entry->AddInstruction(with_environment);
diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc
index 7a930cc..2382b72 100644
--- a/compiler/optimizing/optimizing_compiler.cc
+++ b/compiler/optimizing/optimizing_compiler.cc
@@ -61,6 +61,7 @@
#include "debug/method_debug_info.h"
#include "dex/verification_results.h"
#include "dex/verified_method.h"
+#include "dex_file_types.h"
#include "driver/compiler_driver-inl.h"
#include "driver/compiler_options.h"
#include "driver/dex_compilation_unit.h"
@@ -117,6 +118,7 @@
size_t GetSize() const { return size_; }
const ArenaVector<uint8_t>& GetMemory() const { return memory_; }
+ uint8_t* GetData() { return memory_.data(); }
private:
ArenaVector<uint8_t> memory_;
@@ -624,17 +626,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);
@@ -643,7 +642,9 @@
simplifier,
side_effects,
gvn,
+#ifndef ART_USE_VIXL_ARM_BACKEND
fixups
+#endif
};
RunOptimizations(arm_optimizations, arraysize(arm_optimizations), pass_observer);
break;
@@ -948,7 +949,7 @@
graph->SetArtMethod(method);
ScopedObjectAccess soa(Thread::Current());
interpreter_metadata = method->GetQuickenedInfo(class_linker->GetImagePointerSize());
- uint16_t type_index = method->GetDeclaringClass()->GetDexTypeIndex();
+ dex::TypeIndex type_index = method->GetDeclaringClass()->GetDexTypeIndex();
// Update the dex cache if the type is not in it yet. Note that under AOT,
// the verifier must have set it, but under JIT, there's no guarantee, as we
@@ -1125,7 +1126,7 @@
jit::JitCodeCache* code_cache,
ArtMethod* method,
bool osr) {
- StackHandleScope<2> hs(self);
+ StackHandleScope<3> hs(self);
Handle<mirror::ClassLoader> class_loader(hs.NewHandle(
method->GetDeclaringClass()->GetClassLoader()));
Handle<mirror::DexCache> dex_cache(hs.NewHandle(method->GetDexCache()));
@@ -1171,25 +1172,46 @@
}
size_t stack_map_size = codegen->ComputeStackMapsSize();
- uint8_t* stack_map_data = code_cache->ReserveData(self, stack_map_size, method);
- if (stack_map_data == nullptr) {
+ size_t number_of_roots = codegen->GetNumberOfJitRoots();
+ ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+ // We allocate an object array to ensure the JIT roots that we will collect in EmitJitRoots
+ // will be visible by the GC between EmitLiterals and CommitCode. Once CommitCode is
+ // executed, this array is not needed.
+ Handle<mirror::ObjectArray<mirror::Object>> roots(
+ hs.NewHandle(mirror::ObjectArray<mirror::Object>::Alloc(
+ self, class_linker->GetClassRoot(ClassLinker::kObjectArrayClass), number_of_roots)));
+ if (roots.Get() == nullptr) {
+ // Out of memory, just clear the exception to avoid any Java exception uncaught problems.
+ DCHECK(self->IsExceptionPending());
+ self->ClearException();
+ return false;
+ }
+ uint8_t* stack_map_data = nullptr;
+ uint8_t* roots_data = nullptr;
+ code_cache->ReserveData(
+ self, stack_map_size, number_of_roots, method, &stack_map_data, &roots_data);
+ if (stack_map_data == nullptr || roots_data == nullptr) {
return false;
}
MaybeRecordStat(MethodCompilationStat::kCompiled);
codegen->BuildStackMaps(MemoryRegion(stack_map_data, stack_map_size), *code_item);
+ codegen->EmitJitRoots(code_allocator.GetData(), roots, roots_data, dex_cache);
+
const void* code = code_cache->CommitCode(
self,
method,
stack_map_data,
+ roots_data,
codegen->HasEmptyFrame() ? 0 : codegen->GetFrameSize(),
codegen->GetCoreSpillMask(),
codegen->GetFpuSpillMask(),
code_allocator.GetMemory().data(),
code_allocator.GetSize(),
- osr);
+ osr,
+ roots);
if (code == nullptr) {
- code_cache->ClearData(self, stack_map_data);
+ code_cache->ClearData(self, stack_map_data, roots_data);
return false;
}
diff --git a/compiler/optimizing/prepare_for_register_allocation.cc b/compiler/optimizing/prepare_for_register_allocation.cc
index 0db6088..f9ac3a0 100644
--- a/compiler/optimizing/prepare_for_register_allocation.cc
+++ b/compiler/optimizing/prepare_for_register_allocation.cc
@@ -143,7 +143,7 @@
// - or the load class has only one use.
if (instruction->IsFinalizable() || has_only_one_use || load_class->NeedsAccessCheck()) {
instruction->SetEntrypoint(kQuickAllocObject);
- instruction->ReplaceInput(GetGraph()->GetIntConstant(load_class->GetTypeIndex()), 0);
+ instruction->ReplaceInput(GetGraph()->GetIntConstant(load_class->GetTypeIndex().index_), 0);
if (has_only_one_use) {
// We've just removed the only use of the HLoadClass. Since we don't run DCE after this pass,
// do it manually if possible.
diff --git a/compiler/optimizing/reference_type_propagation.cc b/compiler/optimizing/reference_type_propagation.cc
index d588dea..c191c66 100644
--- a/compiler/optimizing/reference_type_propagation.cc
+++ b/compiler/optimizing/reference_type_propagation.cc
@@ -96,7 +96,7 @@
void VisitBoundType(HBoundType* instr) OVERRIDE;
void VisitNullCheck(HNullCheck* instr) OVERRIDE;
void UpdateReferenceTypeInfo(HInstruction* instr,
- uint16_t type_idx,
+ dex::TypeIndex type_idx,
const DexFile& dex_file,
bool is_exact);
@@ -463,7 +463,7 @@
}
void ReferenceTypePropagation::RTPVisitor::UpdateReferenceTypeInfo(HInstruction* instr,
- uint16_t type_idx,
+ dex::TypeIndex type_idx,
const DexFile& dex_file,
bool is_exact) {
DCHECK_EQ(instr->GetType(), Primitive::kPrimNot);
@@ -484,7 +484,7 @@
static mirror::Class* GetClassFromDexCache(Thread* self,
const DexFile& dex_file,
- uint16_t type_idx,
+ dex::TypeIndex type_idx,
Handle<mirror::DexCache> hint_dex_cache)
REQUIRES_SHARED(Locks::mutator_lock_) {
mirror::DexCache* dex_cache = FindDexCacheWithHint(self, dex_file, hint_dex_cache);
diff --git a/compiler/optimizing/register_allocator_test.cc b/compiler/optimizing/register_allocator_test.cc
index 55ea99e..559f409 100644
--- a/compiler/optimizing/register_allocator_test.cc
+++ b/compiler/optimizing/register_allocator_test.cc
@@ -20,6 +20,7 @@
#include "code_generator.h"
#include "code_generator_x86.h"
#include "dex_file.h"
+#include "dex_file_types.h"
#include "dex_instruction.h"
#include "driver/compiler_options.h"
#include "nodes.h"
@@ -495,7 +496,7 @@
graph->AddBlock(entry);
graph->SetEntryBlock(entry);
HInstruction* parameter = new (allocator) HParameterValue(
- graph->GetDexFile(), 0, 0, Primitive::kPrimNot);
+ graph->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimNot);
entry->AddInstruction(parameter);
HBasicBlock* block = new (allocator) HBasicBlock(graph);
@@ -658,7 +659,7 @@
graph->AddBlock(entry);
graph->SetEntryBlock(entry);
HInstruction* parameter = new (allocator) HParameterValue(
- graph->GetDexFile(), 0, 0, Primitive::kPrimNot);
+ graph->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimNot);
entry->AddInstruction(parameter);
HBasicBlock* block = new (allocator) HBasicBlock(graph);
@@ -742,7 +743,7 @@
graph->AddBlock(entry);
graph->SetEntryBlock(entry);
HInstruction* parameter = new (allocator) HParameterValue(
- graph->GetDexFile(), 0, 0, Primitive::kPrimInt);
+ graph->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimInt);
entry->AddInstruction(parameter);
HInstruction* constant1 = graph->GetIntConstant(1);
@@ -821,9 +822,9 @@
graph->AddBlock(entry);
graph->SetEntryBlock(entry);
HInstruction* first = new (allocator) HParameterValue(
- graph->GetDexFile(), 0, 0, Primitive::kPrimInt);
+ graph->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimInt);
HInstruction* second = new (allocator) HParameterValue(
- graph->GetDexFile(), 0, 0, Primitive::kPrimInt);
+ graph->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimInt);
entry->AddInstruction(first);
entry->AddInstruction(second);
@@ -883,13 +884,13 @@
graph->AddBlock(entry);
graph->SetEntryBlock(entry);
HInstruction* one = new (&allocator) HParameterValue(
- graph->GetDexFile(), 0, 0, Primitive::kPrimInt);
+ graph->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimInt);
HInstruction* two = new (&allocator) HParameterValue(
- graph->GetDexFile(), 0, 0, Primitive::kPrimInt);
+ graph->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimInt);
HInstruction* three = new (&allocator) HParameterValue(
- graph->GetDexFile(), 0, 0, Primitive::kPrimInt);
+ graph->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimInt);
HInstruction* four = new (&allocator) HParameterValue(
- graph->GetDexFile(), 0, 0, Primitive::kPrimInt);
+ graph->GetDexFile(), dex::TypeIndex(0), 0, Primitive::kPrimInt);
entry->AddInstruction(one);
entry->AddInstruction(two);
entry->AddInstruction(three);
diff --git a/compiler/optimizing/sharpening.cc b/compiler/optimizing/sharpening.cc
index 63e4ca6..a127708 100644
--- a/compiler/optimizing/sharpening.cc
+++ b/compiler/optimizing/sharpening.cc
@@ -147,7 +147,7 @@
DCHECK(!load_class->IsInBootImage()) << "HLoadClass should not be optimized before sharpening.";
const DexFile& dex_file = load_class->GetDexFile();
- uint32_t type_index = load_class->GetTypeIndex();
+ dex::TypeIndex type_index = load_class->GetTypeIndex();
bool is_in_dex_cache = false;
bool is_in_boot_image = false;
@@ -197,7 +197,7 @@
// inlined frames are used correctly for OOM stack trace.
// TODO: Write a test for this. Bug: 29416588
desired_load_kind = HLoadClass::LoadKind::kDexCacheAddress;
- void* dex_cache_element_address = &dex_cache->GetResolvedTypes()[type_index];
+ void* dex_cache_element_address = &dex_cache->GetResolvedTypes()[type_index.index_];
address = reinterpret_cast64<uint64_t>(dex_cache_element_address);
}
// AOT app compilation. Check if the class is in the boot image.
@@ -281,7 +281,8 @@
: hs.NewHandle(class_linker->FindDexCache(soa.Self(), dex_file));
if (codegen_->GetCompilerOptions().IsBootImage()) {
- // Compiling boot image. Resolve the string and allocate it if needed.
+ // Compiling boot image. Resolve the string and allocate it if needed, to ensure
+ // the string will be added to the boot image.
DCHECK(!runtime->UseJitCompilation());
mirror::String* string = class_linker->ResolveString(dex_file, string_index, dex_cache);
CHECK(string != nullptr);
@@ -297,10 +298,14 @@
} else if (runtime->UseJitCompilation()) {
// TODO: Make sure we don't set the "compile PIC" flag for JIT as that's bogus.
// DCHECK(!codegen_->GetCompilerOptions().GetCompilePic());
- mirror::String* string = dex_cache->GetResolvedString(string_index);
- if (string != nullptr && runtime->GetHeap()->ObjectIsInBootImageSpace(string)) {
- desired_load_kind = HLoadString::LoadKind::kBootImageAddress;
- address = reinterpret_cast64<uint64_t>(string);
+ mirror::String* string = class_linker->LookupString(dex_file, string_index, dex_cache);
+ if (string != nullptr) {
+ if (runtime->GetHeap()->ObjectIsInBootImageSpace(string)) {
+ desired_load_kind = HLoadString::LoadKind::kBootImageAddress;
+ address = reinterpret_cast64<uint64_t>(string);
+ } else {
+ desired_load_kind = HLoadString::LoadKind::kJitTableAddress;
+ }
}
} else {
// AOT app compilation. Try to lookup the string without allocating if not found.
@@ -322,6 +327,7 @@
case HLoadString::LoadKind::kBootImageLinkTimePcRelative:
case HLoadString::LoadKind::kBssEntry:
case HLoadString::LoadKind::kDexCacheViaMethod:
+ case HLoadString::LoadKind::kJitTableAddress:
load_string->SetLoadKindWithStringReference(load_kind, dex_file, string_index);
break;
case HLoadString::LoadKind::kBootImageAddress:
diff --git a/compiler/utils/arm/assembler_arm_vixl.cc b/compiler/utils/arm/assembler_arm_vixl.cc
index e3b9fb6..c35c393 100644
--- a/compiler/utils/arm/assembler_arm_vixl.cc
+++ b/compiler/utils/arm/assembler_arm_vixl.cc
@@ -43,12 +43,12 @@
}
const uint8_t* ArmVIXLAssembler::CodeBufferBaseAddress() const {
- return vixl_masm_.GetStartAddress<uint8_t*>();
+ return vixl_masm_.GetBuffer().GetStartAddress<const uint8_t*>();
}
void ArmVIXLAssembler::FinalizeInstructions(const MemoryRegion& region) {
// Copy the instructions from the buffer.
- MemoryRegion from(vixl_masm_.GetStartAddress<void*>(), CodeSize());
+ MemoryRegion from(vixl_masm_.GetBuffer()->GetStartAddress<void*>(), CodeSize());
region.CopyFrom(0, from);
}
@@ -365,7 +365,7 @@
if (stack_offset != 0) {
base = temps.Acquire();
DCHECK_EQ(regs & (1u << base.GetCode()), 0u);
- ___ Add(base, sp, stack_offset);
+ ___ Add(base, sp, Operand::From(stack_offset));
}
___ Stm(base, NO_WRITE_BACK, RegisterList(regs));
} else {
@@ -385,7 +385,7 @@
vixl32::Register base = sp;
if (stack_offset != 0) {
base = temps.Acquire();
- ___ Add(base, sp, stack_offset);
+ ___ Add(base, sp, Operand::From(stack_offset));
}
___ Ldm(base, NO_WRITE_BACK, RegisterList(regs));
} else {
@@ -429,5 +429,31 @@
}
}
+void ArmVIXLMacroAssembler::CompareAndBranchIfZero(vixl32::Register rn,
+ vixl32::Label* label,
+ bool is_far_target) {
+ if (!is_far_target && rn.IsLow() && !label->IsBound()) {
+ // In T32, Cbz/Cbnz instructions have following limitations:
+ // - There are only 7 bits (i:imm5:0) to encode branch target address (cannot be far target).
+ // - Only low registers (i.e R0 .. R7) can be encoded.
+ // - Only forward branches (unbound labels) are supported.
+ Cbz(rn, label);
+ return;
+ }
+ Cmp(rn, 0);
+ B(eq, label);
+}
+
+void ArmVIXLMacroAssembler::CompareAndBranchIfNonZero(vixl32::Register rn,
+ vixl32::Label* label,
+ bool is_far_target) {
+ if (!is_far_target && rn.IsLow() && !label->IsBound()) {
+ Cbnz(rn, label);
+ return;
+ }
+ Cmp(rn, 0);
+ B(ne, label);
+}
+
} // namespace arm
} // namespace art
diff --git a/compiler/utils/arm/assembler_arm_vixl.h b/compiler/utils/arm/assembler_arm_vixl.h
index e020628..b4a4abc 100644
--- a/compiler/utils/arm/assembler_arm_vixl.h
+++ b/compiler/utils/arm/assembler_arm_vixl.h
@@ -37,6 +37,25 @@
namespace art {
namespace arm {
+class ArmVIXLMacroAssembler FINAL : public vixl32::MacroAssembler {
+ public:
+ // The following interfaces can generate CMP+Bcc or Cbz/Cbnz.
+ // CMP+Bcc are generated by default.
+ // If a hint is given (is_far_target = false) and rn and label can all fit into Cbz/Cbnz,
+ // then Cbz/Cbnz is generated.
+ // Prefer following interfaces to using vixl32::MacroAssembler::Cbz/Cbnz.
+ // In T32, Cbz/Cbnz instructions have following limitations:
+ // - Far targets, which are over 126 bytes away, are not supported.
+ // - Only low registers can be encoded.
+ // - Backward branches are not supported.
+ void CompareAndBranchIfZero(vixl32::Register rn,
+ vixl32::Label* label,
+ bool is_far_target = true);
+ void CompareAndBranchIfNonZero(vixl32::Register rn,
+ vixl32::Label* label,
+ bool is_far_target = true);
+};
+
class ArmVIXLAssembler FINAL : public Assembler {
private:
class ArmException;
@@ -48,7 +67,7 @@
}
virtual ~ArmVIXLAssembler() {}
- vixl32::MacroAssembler* GetVIXLAssembler() { return &vixl_masm_; }
+ ArmVIXLMacroAssembler* GetVIXLAssembler() { return &vixl_masm_; }
void FinalizeCode() OVERRIDE;
// Size of generated code.
@@ -117,7 +136,7 @@
private:
// VIXL assembler.
- vixl32::MacroAssembler vixl_masm_;
+ ArmVIXLMacroAssembler vixl_masm_;
};
// Thread register declaration.
diff --git a/compiler/utils/arm/jni_macro_assembler_arm.cc b/compiler/utils/arm/jni_macro_assembler_arm.cc
index cf7a4d1..3f425df 100644
--- a/compiler/utils/arm/jni_macro_assembler_arm.cc
+++ b/compiler/utils/arm/jni_macro_assembler_arm.cc
@@ -594,6 +594,41 @@
__ b(slow->Entry(), NE);
}
+std::unique_ptr<JNIMacroLabel> ArmJNIMacroAssembler::CreateLabel() {
+ return std::unique_ptr<JNIMacroLabel>(new ArmJNIMacroLabel());
+}
+
+void ArmJNIMacroAssembler::Jump(JNIMacroLabel* label) {
+ CHECK(label != nullptr);
+ __ b(ArmJNIMacroLabel::Cast(label)->AsArm());
+}
+
+void ArmJNIMacroAssembler::Jump(JNIMacroLabel* label,
+ JNIMacroUnaryCondition condition,
+ ManagedRegister test) {
+ CHECK(label != nullptr);
+
+ arm::Condition arm_cond;
+ switch (condition) {
+ case JNIMacroUnaryCondition::kZero:
+ arm_cond = EQ;
+ break;
+ case JNIMacroUnaryCondition::kNotZero:
+ arm_cond = NE;
+ break;
+ default:
+ LOG(FATAL) << "Not implemented condition: " << static_cast<int>(condition);
+ UNREACHABLE();
+ }
+ __ cmp(test.AsArm().AsCoreRegister(), ShifterOperand(0));
+ __ b(ArmJNIMacroLabel::Cast(label)->AsArm(), arm_cond);
+}
+
+void ArmJNIMacroAssembler::Bind(JNIMacroLabel* label) {
+ CHECK(label != nullptr);
+ __ Bind(ArmJNIMacroLabel::Cast(label)->AsArm());
+}
+
#undef __
void ArmExceptionSlowPath::Emit(Assembler* sasm) {
diff --git a/compiler/utils/arm/jni_macro_assembler_arm.h b/compiler/utils/arm/jni_macro_assembler_arm.h
index 4471906..809ac8b 100644
--- a/compiler/utils/arm/jni_macro_assembler_arm.h
+++ b/compiler/utils/arm/jni_macro_assembler_arm.h
@@ -25,6 +25,7 @@
#include "base/enums.h"
#include "base/macros.h"
#include "utils/jni_macro_assembler.h"
+#include "utils/label.h"
#include "offsets.h"
namespace art {
@@ -159,10 +160,26 @@
void MemoryBarrier(ManagedRegister scratch) OVERRIDE;
+ // Create a new label that can be used with Jump/Bind calls.
+ std::unique_ptr<JNIMacroLabel> CreateLabel() OVERRIDE;
+ // Emit an unconditional jump to the label.
+ void Jump(JNIMacroLabel* label) OVERRIDE;
+ // Emit a conditional jump to the label by applying a unary condition test to the register.
+ void Jump(JNIMacroLabel* label, JNIMacroUnaryCondition cond, ManagedRegister test) OVERRIDE;
+ // Code at this offset will serve as the target for the Jump call.
+ void Bind(JNIMacroLabel* label) OVERRIDE;
+
private:
std::unique_ptr<ArmAssembler> asm_;
};
+class ArmJNIMacroLabel FINAL : public JNIMacroLabelCommon<ArmJNIMacroLabel, art::Label, kArm> {
+ public:
+ art::Label* AsArm() {
+ return AsPlatformLabel();
+ }
+};
+
} // namespace arm
} // namespace art
diff --git a/compiler/utils/arm/jni_macro_assembler_arm_vixl.cc b/compiler/utils/arm/jni_macro_assembler_arm_vixl.cc
index 8a9fd90..f20ed0a 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,
@@ -168,6 +168,8 @@
CHECK_EQ(0u, size);
} else if (src.IsCoreRegister()) {
CHECK_EQ(4u, size);
+ UseScratchRegisterScope temps(asm_.GetVIXLAssembler());
+ temps.Exclude(src.AsVIXLRegister());
asm_.StoreToOffset(kStoreWord, src.AsVIXLRegister(), sp, dest.Int32Value());
} else if (src.IsRegisterPair()) {
CHECK_EQ(8u, size);
@@ -186,12 +188,16 @@
void ArmVIXLJNIMacroAssembler::StoreRef(FrameOffset dest, ManagedRegister msrc) {
ArmManagedRegister src = msrc.AsArm();
CHECK(src.IsCoreRegister()) << src;
+ UseScratchRegisterScope temps(asm_.GetVIXLAssembler());
+ temps.Exclude(src.AsVIXLRegister());
asm_.StoreToOffset(kStoreWord, src.AsVIXLRegister(), sp, dest.Int32Value());
}
void ArmVIXLJNIMacroAssembler::StoreRawPtr(FrameOffset dest, ManagedRegister msrc) {
ArmManagedRegister src = msrc.AsArm();
CHECK(src.IsCoreRegister()) << src;
+ UseScratchRegisterScope temps(asm_.GetVIXLAssembler());
+ temps.Exclude(src.AsVIXLRegister());
asm_.StoreToOffset(kStoreWord, src.AsVIXLRegister(), sp, dest.Int32Value());
}
@@ -202,6 +208,8 @@
ArmManagedRegister src = msrc.AsArm();
ArmManagedRegister scratch = mscratch.AsArm();
asm_.StoreToOffset(kStoreWord, src.AsVIXLRegister(), sp, dest.Int32Value());
+ UseScratchRegisterScope temps(asm_.GetVIXLAssembler());
+ temps.Exclude(scratch.AsVIXLRegister());
asm_.LoadFromOffset(kLoadWord, scratch.AsVIXLRegister(), sp, in_off.Int32Value());
asm_.StoreToOffset(kStoreWord, scratch.AsVIXLRegister(), sp, dest.Int32Value() + 4);
}
@@ -210,6 +218,8 @@
FrameOffset src,
ManagedRegister mscratch) {
ArmManagedRegister scratch = mscratch.AsArm();
+ UseScratchRegisterScope temps(asm_.GetVIXLAssembler());
+ temps.Exclude(scratch.AsVIXLRegister());
asm_.LoadFromOffset(kLoadWord, scratch.AsVIXLRegister(), sp, src.Int32Value());
asm_.StoreToOffset(kStoreWord, scratch.AsVIXLRegister(), sp, dest.Int32Value());
}
@@ -220,6 +230,8 @@
bool unpoison_reference) {
ArmManagedRegister dst = dest.AsArm();
CHECK(dst.IsCoreRegister() && dst.IsCoreRegister()) << dst;
+ UseScratchRegisterScope temps(asm_.GetVIXLAssembler());
+ temps.Exclude(dst.AsVIXLRegister(), base.AsArm().AsVIXLRegister());
asm_.LoadFromOffset(kLoadWord,
dst.AsVIXLRegister(),
base.AsArm().AsVIXLRegister(),
@@ -246,6 +258,8 @@
ManagedRegister scratch) {
ArmManagedRegister mscratch = scratch.AsArm();
CHECK(mscratch.IsCoreRegister()) << mscratch;
+ UseScratchRegisterScope temps(asm_.GetVIXLAssembler());
+ temps.Exclude(mscratch.AsVIXLRegister());
asm_.LoadImmediate(mscratch.AsVIXLRegister(), imm);
asm_.StoreToOffset(kStoreWord, mscratch.AsVIXLRegister(), sp, dest.Int32Value());
}
@@ -263,6 +277,8 @@
void ArmVIXLJNIMacroAssembler::LoadRawPtrFromThread(ManagedRegister m_dst, ThreadOffset32 offs) {
ArmManagedRegister dst = m_dst.AsArm();
CHECK(dst.IsCoreRegister()) << dst;
+ UseScratchRegisterScope temps(asm_.GetVIXLAssembler());
+ temps.Exclude(dst.AsVIXLRegister());
asm_.LoadFromOffset(kLoadWord, dst.AsVIXLRegister(), tr, offs.Int32Value());
}
@@ -271,6 +287,8 @@
ManagedRegister mscratch) {
ArmManagedRegister scratch = mscratch.AsArm();
CHECK(scratch.IsCoreRegister()) << scratch;
+ UseScratchRegisterScope temps(asm_.GetVIXLAssembler());
+ temps.Exclude(scratch.AsVIXLRegister());
asm_.LoadFromOffset(kLoadWord, scratch.AsVIXLRegister(), tr, thr_offs.Int32Value());
asm_.StoreToOffset(kStoreWord, scratch.AsVIXLRegister(), sp, fr_offs.Int32Value());
}
@@ -286,6 +304,8 @@
ManagedRegister mscratch) {
ArmManagedRegister scratch = mscratch.AsArm();
CHECK(scratch.IsCoreRegister()) << scratch;
+ UseScratchRegisterScope temps(asm_.GetVIXLAssembler());
+ temps.Exclude(scratch.AsVIXLRegister());
asm_.AddConstant(scratch.AsVIXLRegister(), sp, fr_offs.Int32Value());
asm_.StoreToOffset(kStoreWord, scratch.AsVIXLRegister(), tr, thr_offs.Int32Value());
}
@@ -312,6 +332,8 @@
if (!dst.Equals(src)) {
if (dst.IsCoreRegister()) {
CHECK(src.IsCoreRegister()) << src;
+ UseScratchRegisterScope temps(asm_.GetVIXLAssembler());
+ temps.Exclude(dst.AsVIXLRegister());
___ Mov(dst.AsVIXLRegister(), src.AsVIXLRegister());
} else if (dst.IsDRegister()) {
if (src.IsDRegister()) {
@@ -351,6 +373,8 @@
ArmManagedRegister temp = scratch.AsArm();
CHECK(temp.IsCoreRegister()) << temp;
CHECK(size == 4 || size == 8) << size;
+ UseScratchRegisterScope temps(asm_.GetVIXLAssembler());
+ temps.Exclude(temp.AsVIXLRegister());
if (size == 4) {
asm_.LoadFromOffset(kLoadWord, temp.AsVIXLRegister(), sp, src.Int32Value());
asm_.StoreToOffset(kStoreWord, temp.AsVIXLRegister(), sp, dest.Int32Value());
@@ -414,6 +438,8 @@
ArmManagedRegister in_reg = min_reg.AsArm();
CHECK(in_reg.IsNoRegister() || in_reg.IsCoreRegister()) << in_reg;
CHECK(out_reg.IsCoreRegister()) << out_reg;
+ UseScratchRegisterScope temps(asm_.GetVIXLAssembler());
+ temps.Exclude(out_reg.AsVIXLRegister());
if (null_allowed) {
// Null values get a handle scope entry value of 0. Otherwise, the handle scope entry is
// the address in the handle scope holding the reference.
@@ -425,6 +451,8 @@
handle_scope_offset.Int32Value());
in_reg = out_reg;
}
+
+ temps.Exclude(in_reg.AsVIXLRegister());
___ Cmp(in_reg.AsVIXLRegister(), 0);
if (asm_.ShifterOperandCanHold(ADD, handle_scope_offset.Int32Value(), kCcDontCare)) {
@@ -457,6 +485,8 @@
bool null_allowed) {
ArmManagedRegister scratch = mscratch.AsArm();
CHECK(scratch.IsCoreRegister()) << scratch;
+ UseScratchRegisterScope temps(asm_.GetVIXLAssembler());
+ temps.Exclude(scratch.AsVIXLRegister());
if (null_allowed) {
asm_.LoadFromOffset(kLoadWord, scratch.AsVIXLRegister(), sp, handle_scope_offset.Int32Value());
// Null values get a handle scope entry value of 0. Otherwise, the handle scope entry is
@@ -503,6 +533,8 @@
ArmManagedRegister scratch = mscratch.AsArm();
CHECK(base.IsCoreRegister()) << base;
CHECK(scratch.IsCoreRegister()) << scratch;
+ UseScratchRegisterScope temps(asm_.GetVIXLAssembler());
+ temps.Exclude(scratch.AsVIXLRegister());
asm_.LoadFromOffset(kLoadWord,
scratch.AsVIXLRegister(),
base.AsVIXLRegister(),
@@ -514,6 +546,8 @@
void ArmVIXLJNIMacroAssembler::Call(FrameOffset base, Offset offset, ManagedRegister mscratch) {
ArmManagedRegister scratch = mscratch.AsArm();
CHECK(scratch.IsCoreRegister()) << scratch;
+ UseScratchRegisterScope temps(asm_.GetVIXLAssembler());
+ temps.Exclude(scratch.AsVIXLRegister());
// Call *(*(SP + base) + offset)
asm_.LoadFromOffset(kLoadWord, scratch.AsVIXLRegister(), sp, base.Int32Value());
asm_.LoadFromOffset(kLoadWord,
@@ -541,6 +575,8 @@
void ArmVIXLJNIMacroAssembler::ExceptionPoll(ManagedRegister m_scratch, size_t stack_adjust) {
CHECK_ALIGNED(stack_adjust, kStackAlignment);
ArmManagedRegister scratch = m_scratch.AsArm();
+ UseScratchRegisterScope temps(asm_.GetVIXLAssembler());
+ temps.Exclude(scratch.AsVIXLRegister());
exception_blocks_.emplace_back(
new ArmVIXLJNIMacroAssembler::ArmException(scratch, stack_adjust));
asm_.LoadFromOffset(kLoadWord,
@@ -574,10 +610,12 @@
switch (condition) {
case JNIMacroUnaryCondition::kZero:
- ___ Cbz(test.AsArm().AsVIXLRegister(), ArmVIXLJNIMacroLabel::Cast(label)->AsArm());
+ ___ CompareAndBranchIfZero(test.AsArm().AsVIXLRegister(),
+ ArmVIXLJNIMacroLabel::Cast(label)->AsArm());
break;
case JNIMacroUnaryCondition::kNotZero:
- ___ Cbnz(test.AsArm().AsVIXLRegister(), ArmVIXLJNIMacroLabel::Cast(label)->AsArm());
+ ___ CompareAndBranchIfNonZero(test.AsArm().AsVIXLRegister(),
+ ArmVIXLJNIMacroLabel::Cast(label)->AsArm());
break;
default:
LOG(FATAL) << "Not implemented unary condition: " << static_cast<int>(condition);
@@ -596,11 +634,14 @@
if (exception->stack_adjust_ != 0) { // Fix up the frame.
DecreaseFrameSize(exception->stack_adjust_);
}
+
+ UseScratchRegisterScope temps(asm_.GetVIXLAssembler());
+ temps.Exclude(exception->scratch_.AsVIXLRegister());
// Pass exception object as argument.
// Don't care about preserving r0 as this won't return.
___ Mov(r0, exception->scratch_.AsVIXLRegister());
+ temps.Include(exception->scratch_.AsVIXLRegister());
// TODO: check that exception->scratch_ is dead by this point.
- UseScratchRegisterScope temps(asm_.GetVIXLAssembler());
vixl32::Register temp = temps.Acquire();
___ Ldr(temp,
MemOperand(tr,
@@ -622,6 +663,9 @@
} else if (dest.IsCoreRegister()) {
CHECK(!dest.AsVIXLRegister().Is(sp)) << dest;
+ UseScratchRegisterScope temps(asm_.GetVIXLAssembler());
+ temps.Exclude(dest.AsVIXLRegister());
+
if (size == 1u) {
___ Ldrb(dest.AsVIXLRegister(), MemOperand(base, offset));
} else {
diff --git a/compiler/utils/arm64/assembler_arm64.cc b/compiler/utils/arm64/assembler_arm64.cc
index f91bcfa..6ed0e9b 100644
--- a/compiler/utils/arm64/assembler_arm64.cc
+++ b/compiler/utils/arm64/assembler_arm64.cc
@@ -40,12 +40,12 @@
}
const uint8_t* Arm64Assembler::CodeBufferBaseAddress() const {
- return vixl_masm_.GetStartAddress<uint8_t*>();
+ return vixl_masm_.GetBuffer().GetStartAddress<const uint8_t*>();
}
void Arm64Assembler::FinalizeInstructions(const MemoryRegion& region) {
// Copy the instructions from the buffer.
- MemoryRegion from(vixl_masm_.GetStartAddress<void*>(), CodeSize());
+ MemoryRegion from(vixl_masm_.GetBuffer()->GetStartAddress<void*>(), CodeSize());
region.CopyFrom(0, from);
}
diff --git a/compiler/utils/assembler_thumb_test.cc b/compiler/utils/assembler_thumb_test.cc
index 10bed13..50a1d9f 100644
--- a/compiler/utils/assembler_thumb_test.cc
+++ b/compiler/utils/assembler_thumb_test.cc
@@ -1753,7 +1753,10 @@
__ LoadFromOffset(kLoadWordPair, R2, R4, 0x40400);
__ LoadFromOffset(kLoadWordPair, R4, R4, 0x40400);
+ vixl::aarch32::UseScratchRegisterScope temps(assembler.asm_.GetVIXLAssembler());
+ temps.Exclude(R12);
__ LoadFromOffset(kLoadWord, R0, R12, 12); // 32-bit because of R12.
+ temps.Include(R12);
__ LoadFromOffset(kLoadWord, R2, R4, 0xa4 - 0x100000);
__ LoadFromOffset(kLoadSignedByte, R2, R4, 12);
@@ -1783,7 +1786,10 @@
__ StoreToOffset(kStoreWordPair, R2, R4, 0x40400);
__ StoreToOffset(kStoreWordPair, R4, R4, 0x40400);
+ vixl::aarch32::UseScratchRegisterScope temps(assembler.asm_.GetVIXLAssembler());
+ temps.Exclude(R12);
__ StoreToOffset(kStoreWord, R0, R12, 12); // 32-bit because of R12.
+ temps.Include(R12);
__ StoreToOffset(kStoreWord, R2, R4, 0xa4 - 0x100000);
__ StoreToOffset(kStoreByte, R2, R4, 12);
diff --git a/compiler/utils/jni_macro_assembler.cc b/compiler/utils/jni_macro_assembler.cc
index 2f154fb..1b74313 100644
--- a/compiler/utils/jni_macro_assembler.cc
+++ b/compiler/utils/jni_macro_assembler.cc
@@ -20,7 +20,7 @@
#include <vector>
#ifdef ART_ENABLE_CODEGEN_arm
-#include "arm/jni_macro_assembler_arm_vixl.h"
+#include "arm/jni_macro_assembler_arm.h"
#endif
#ifdef ART_ENABLE_CODEGEN_arm64
#include "arm64/jni_macro_assembler_arm64.h"
@@ -58,7 +58,7 @@
#ifdef ART_ENABLE_CODEGEN_arm
case kArm:
case kThumb2:
- return MacroAsm32UniquePtr(new (arena) arm::ArmVIXLJNIMacroAssembler(arena));
+ return MacroAsm32UniquePtr(new (arena) arm::ArmJNIMacroAssembler(arena, instruction_set));
#endif
#ifdef ART_ENABLE_CODEGEN_mips
case kMips:
diff --git a/compiler/utils/test_dex_file_builder_test.cc b/compiler/utils/test_dex_file_builder_test.cc
index da4ac79..922f8b1 100644
--- a/compiler/utils/test_dex_file_builder_test.cc
+++ b/compiler/utils/test_dex_file_builder_test.cc
@@ -62,7 +62,8 @@
};
ASSERT_EQ(arraysize(expected_types), dex_file->NumTypeIds());
for (size_t i = 0; i != arraysize(expected_types); ++i) {
- EXPECT_STREQ(expected_types[i], dex_file->GetTypeDescriptor(dex_file->GetTypeId(i))) << i;
+ EXPECT_STREQ(expected_types[i],
+ dex_file->GetTypeDescriptor(dex_file->GetTypeId(dex::TypeIndex(i)))) << i;
}
ASSERT_EQ(1u, dex_file->NumFieldIds());
diff --git a/compiler/utils/type_reference.h b/compiler/utils/type_reference.h
index d0c1656..a0fa1a4 100644
--- a/compiler/utils/type_reference.h
+++ b/compiler/utils/type_reference.h
@@ -20,6 +20,7 @@
#include <stdint.h>
#include "base/logging.h"
+#include "dex_file_types.h"
#include "string_reference.h"
namespace art {
@@ -28,10 +29,10 @@
// A type is located by its DexFile and the string_ids_ table index into that DexFile.
struct TypeReference {
- TypeReference(const DexFile* file, uint32_t index) : dex_file(file), type_index(index) { }
+ TypeReference(const DexFile* file, dex::TypeIndex index) : dex_file(file), type_index(index) { }
const DexFile* dex_file;
- uint32_t type_index;
+ dex::TypeIndex type_index;
};
// Compare the actual referenced type names. Used for type reference deduplication.
diff --git a/compiler/verifier_deps_test.cc b/compiler/verifier_deps_test.cc
index 6b690aa..525a2ee 100644
--- a/compiler/verifier_deps_test.cc
+++ b/compiler/verifier_deps_test.cc
@@ -23,6 +23,7 @@
#include "compiler/driver/compiler_driver.h"
#include "compiler_callbacks.h"
#include "dex_file.h"
+#include "dex_file_types.h"
#include "handle_scope-inl.h"
#include "verifier/method_verifier-inl.h"
#include "mirror/class_loader.h"
@@ -82,10 +83,13 @@
// The compiler driver handles the verifier deps in the callbacks, so
// remove what this class did for unit testing.
verifier_deps_.reset(nullptr);
- callbacks_->SetVerifierDeps(nullptr);
- compiler_driver_->Verify(class_loader_, dex_files_, deps, &timings);
+ callbacks_->SetVerifierDeps(deps);
+ compiler_driver_->Verify(class_loader_, dex_files_, &timings);
// The compiler driver may have updated the VerifierDeps in the callback object.
- verifier_deps_.reset(callbacks_->GetVerifierDeps());
+ if (callbacks_->GetVerifierDeps() != deps) {
+ verifier_deps_.reset(callbacks_->GetVerifierDeps());
+ }
+ callbacks_->SetVerifierDeps(nullptr);
}
void SetVerifierDeps(const std::vector<const DexFile*>& dex_files) {
@@ -153,6 +157,7 @@
}
CHECK(method != nullptr);
+ Thread::Current()->SetVerifierDeps(callbacks_->GetVerifierDeps());
MethodVerifier verifier(Thread::Current(),
primary_dex_file_,
dex_cache_handle,
@@ -168,6 +173,7 @@
false /* verify to dump */,
true /* allow_thread_suspension */);
verifier.Verify();
+ Thread::Current()->SetVerifierDeps(nullptr);
return !verifier.HasFailures();
}
@@ -207,8 +213,8 @@
hs.NewHandle(soa.Decode<mirror::ClassLoader>(class_loader_)));
MutableHandle<mirror::Class> cls(hs.NewHandle<mirror::Class>(nullptr));
for (const DexFile* dex_file : dex_files_) {
- const std::vector<uint16_t>& unverified_classes = deps.GetUnverifiedClasses(*dex_file);
- std::set<uint16_t> set(unverified_classes.begin(), unverified_classes.end());
+ const std::vector<dex::TypeIndex>& unverified_classes = deps.GetUnverifiedClasses(*dex_file);
+ std::set<dex::TypeIndex> set(unverified_classes.begin(), unverified_classes.end());
for (uint32_t i = 0; i < dex_file->NumClassDefs(); ++i) {
const DexFile::ClassDef& class_def = dex_file->GetClassDef(i);
const char* descriptor = dex_file->GetClassDescriptor(class_def);
@@ -228,10 +234,9 @@
bool HasUnverifiedClass(const std::string& cls) {
const DexFile::TypeId* type_id = primary_dex_file_->FindTypeId(cls.c_str());
DCHECK(type_id != nullptr);
- uint16_t index = primary_dex_file_->GetIndexForTypeId(*type_id);
- MutexLock mu(Thread::Current(), *Locks::verifier_deps_lock_);
+ dex::TypeIndex index = primary_dex_file_->GetIndexForTypeId(*type_id);
for (const auto& dex_dep : verifier_deps_->dex_deps_) {
- for (uint16_t entry : dex_dep.second->unverified_classes_) {
+ for (dex::TypeIndex entry : dex_dep.second->unverified_classes_) {
if (index == entry) {
return true;
}
@@ -245,7 +250,6 @@
bool HasAssignable(const std::string& expected_destination,
const std::string& expected_source,
bool expected_is_assignable) {
- MutexLock mu(Thread::Current(), *Locks::verifier_deps_lock_);
for (auto& dex_dep : verifier_deps_->dex_deps_) {
const DexFile& dex_file = *dex_dep.first;
auto& storage = expected_is_assignable ? dex_dep.second->assignable_types_
@@ -267,7 +271,6 @@
bool HasClass(const std::string& expected_klass,
bool expected_resolved,
const std::string& expected_access_flags = "") {
- MutexLock mu(Thread::Current(), *Locks::verifier_deps_lock_);
for (auto& dex_dep : verifier_deps_->dex_deps_) {
for (auto& entry : dex_dep.second->classes_) {
if (expected_resolved != entry.IsResolved()) {
@@ -302,7 +305,6 @@
bool expected_resolved,
const std::string& expected_access_flags = "",
const std::string& expected_decl_klass = "") {
- MutexLock mu(Thread::Current(), *Locks::verifier_deps_lock_);
for (auto& dex_dep : verifier_deps_->dex_deps_) {
for (auto& entry : dex_dep.second->fields_) {
if (expected_resolved != entry.IsResolved()) {
@@ -356,7 +358,6 @@
bool expected_resolved,
const std::string& expected_access_flags = "",
const std::string& expected_decl_klass = "") {
- MutexLock mu(Thread::Current(), *Locks::verifier_deps_lock_);
for (auto& dex_dep : verifier_deps_->dex_deps_) {
auto& storage = (expected_kind == "direct") ? dex_dep.second->direct_methods_
: (expected_kind == "virtual") ? dex_dep.second->virtual_methods_
@@ -405,13 +406,10 @@
}
size_t NumberOfCompiledDexFiles() {
- MutexLock mu(Thread::Current(), *Locks::verifier_deps_lock_);
return verifier_deps_->dex_deps_.size();
}
size_t HasEachKindOfRecord() {
- MutexLock mu(Thread::Current(), *Locks::verifier_deps_lock_);
-
bool has_strings = false;
bool has_assignability = false;
bool has_classes = false;
@@ -462,8 +460,6 @@
ScopedObjectAccess soa(Thread::Current());
LoadDexFile(&soa);
- MutexLock mu(Thread::Current(), *Locks::verifier_deps_lock_);
-
uint32_t id_Main1 = verifier_deps_->GetIdFromString(*primary_dex_file_, "LMain;");
ASSERT_LT(id_Main1, primary_dex_file_->NumStringIds());
ASSERT_EQ("LMain;", verifier_deps_->GetStringFromId(*primary_dex_file_, id_Main1));
diff --git a/dex2oat/Android.bp b/dex2oat/Android.bp
index 05a5d0f..0924aec 100644
--- a/dex2oat/Android.bp
+++ b/dex2oat/Android.bp
@@ -89,6 +89,7 @@
],
static_libs: [
"libart-compiler",
+ "libart-dexlayout",
"libart",
"libvixl-arm",
"libvixl-arm64",
@@ -118,6 +119,7 @@
],
static_libs: [
"libartd-compiler",
+ "libartd-dexlayout",
"libartd",
"libvixld-arm",
"libvixld-arm64",
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index 65703a2..9e6032f 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -78,6 +78,7 @@
#include "ScopedLocalRef.h"
#include "scoped_thread_state_change-inl.h"
#include "utils.h"
+#include "vdex_file.h"
#include "verifier/verifier_deps.h"
#include "well_known_classes.h"
#include "zip_archive.h"
@@ -270,6 +271,7 @@
"|balanced"
"|speed-profile"
"|speed"
+ "|layout-profile"
"|everything-profile"
"|everything):");
UsageError(" select compiler filter.");
@@ -519,6 +521,7 @@
oat_fd_(-1),
input_vdex_fd_(-1),
output_vdex_fd_(-1),
+ input_vdex_file_(nullptr),
zip_fd_(-1),
image_base_(0U),
image_classes_zip_filename_(nullptr),
@@ -709,6 +712,10 @@
Usage("Output must be supplied with either --oat-file or --oat-fd");
}
+ if (input_vdex_fd_ != -1 && !input_vdex_.empty()) {
+ Usage("Can't have both --input-vdex-fd and --input-vdex");
+ }
+
if (!oat_filenames_.empty() && oat_fd_ != -1) {
Usage("--oat-file should not be used with --oat-fd");
}
@@ -1122,6 +1129,8 @@
zip_location_ = option.substr(strlen("--zip-location=")).data();
} else if (option.starts_with("--input-vdex-fd=")) {
ParseInputVdexFd(option);
+ } else if (option.starts_with("--input-vdex=")) {
+ input_vdex_ = option.substr(strlen("--input-vdex=")).data();
} else if (option.starts_with("--output-vdex-fd=")) {
ParseOutputVdexFd(option);
} else if (option.starts_with("--oat-file=")) {
@@ -1265,6 +1274,17 @@
return false;
}
oat_files_.push_back(std::move(oat_file));
+ DCHECK_EQ(input_vdex_fd_, -1);
+ if (!input_vdex_.empty()) {
+ std::string error_msg;
+ input_vdex_file_.reset(VdexFile::Open(input_vdex_,
+ /* writable */ false,
+ /* low_4gb */ false,
+ &error_msg));
+ if (input_vdex_file_ != nullptr && !input_vdex_file_->IsValid()) {
+ input_vdex_file_.reset(nullptr);
+ }
+ }
DCHECK_EQ(output_vdex_fd_, -1);
std::string vdex_filename = ReplaceFileExtension(oat_filename, "vdex");
@@ -1292,6 +1312,31 @@
}
oat_files_.push_back(std::move(oat_file));
+ DCHECK_NE(input_vdex_fd_, output_vdex_fd_);
+ if (input_vdex_fd_ != -1) {
+ struct stat s;
+ int rc = TEMP_FAILURE_RETRY(fstat(input_vdex_fd_, &s));
+ if (rc == -1) {
+ PLOG(WARNING) << "Failed getting length of vdex file";
+ } else {
+ std::string error_msg;
+ input_vdex_file_.reset(VdexFile::Open(input_vdex_fd_,
+ s.st_size,
+ "vdex",
+ /* writable */ false,
+ /* low_4gb */ false,
+ &error_msg));
+ // If there's any problem with the passed vdex, just warn and proceed
+ // without it.
+ if (input_vdex_file_ == nullptr) {
+ PLOG(WARNING) << "Failed opening vdex file " << error_msg;
+ } else if (!input_vdex_file_->IsValid()) {
+ PLOG(WARNING) << "Existing vdex file is invalid";
+ input_vdex_file_.reset(nullptr);
+ }
+ }
+ }
+
DCHECK_NE(output_vdex_fd_, -1);
std::string vdex_location = ReplaceFileExtension(oat_location_, "vdex");
std::unique_ptr<File> vdex_file(new File(output_vdex_fd_, vdex_location, /* check_usage */ true));
@@ -1387,7 +1432,6 @@
// boot class path.
bool Setup() {
TimingLogger::ScopedTiming t("dex2oat Setup", timings_);
- art::MemMap::Init(); // For ZipEntry::ExtractToMemMap.
if (!PrepareImageClasses() || !PrepareCompiledClasses() || !PrepareCompiledMethods()) {
return false;
@@ -1479,13 +1523,18 @@
// Unzip or copy dex files straight to the oat file.
std::unique_ptr<MemMap> opened_dex_files_map;
std::vector<std::unique_ptr<const DexFile>> opened_dex_files;
+ // No need to verify the dex file for:
+ // 1) dexlayout, which already verified it
+ // 2) when we have a vdex file, which means it was already verified.
+ bool verify = compiler_options_->GetCompilerFilter() != CompilerFilter::kLayoutProfile &&
+ (input_vdex_file_ == nullptr);
if (!oat_writers_[i]->WriteAndOpenDexFiles(
kIsVdexEnabled ? vdex_files_[i].get() : oat_files_[i].get(),
rodata_.back(),
instruction_set_,
instruction_set_features_.get(),
key_value_store_.get(),
- /* verify */ true,
+ verify,
&opened_dex_files_map,
&opened_dex_files)) {
return false;
@@ -1585,6 +1634,9 @@
dex_caches_.push_back(soa.AddLocalReference<jobject>(
class_linker->RegisterDexFile(*dex_file,
soa.Decode<mirror::ClassLoader>(class_loader_).Ptr())));
+ // Pre-register dex files so that we can access verification results without locks during
+ // compilation and verification.
+ verification_results_->PreRegisterDexFile(dex_file);
}
return true;
@@ -1662,7 +1714,7 @@
swap_fd_,
profile_compilation_info_.get()));
driver_->SetDexFilesForOatFile(dex_files_);
- driver_->CompileAll(class_loader_, dex_files_, /* verifier_deps */ nullptr, timings_);
+ driver_->CompileAll(class_loader_, dex_files_, input_vdex_file_.get(), timings_);
}
// Notes on the interleaving of creating the images and oat files to
@@ -2235,7 +2287,14 @@
bool AddDexFileSources() {
TimingLogger::ScopedTiming t2("AddDexFileSources", timings_);
- if (zip_fd_ != -1) {
+ if (input_vdex_file_ != nullptr) {
+ DCHECK_EQ(oat_writers_.size(), 1u);
+ const std::string& name = zip_location_.empty() ? dex_locations_[0] : zip_location_;
+ DCHECK(!name.empty());
+ if (!oat_writers_[0]->AddVdexDexFilesSource(*input_vdex_file_.get(), name.c_str())) {
+ return false;
+ }
+ } else if (zip_fd_ != -1) {
DCHECK_EQ(oat_writers_.size(), 1u);
if (!oat_writers_[0]->AddZippedDexFilesSource(File(zip_fd_, /* check_usage */ false),
zip_location_.c_str())) {
@@ -2273,7 +2332,9 @@
compiler_options_.get(),
oat_file.get()));
elf_writers_.back()->Start();
- oat_writers_.emplace_back(new OatWriter(IsBootImage(), timings_));
+ bool do_dexlayout = compiler_options_->GetCompilerFilter() == CompilerFilter::kLayoutProfile;
+ oat_writers_.emplace_back(new OatWriter(
+ IsBootImage(), timings_, do_dexlayout ? profile_compilation_info_.get() : nullptr));
}
}
@@ -2591,6 +2652,8 @@
int oat_fd_;
int input_vdex_fd_;
int output_vdex_fd_;
+ std::string input_vdex_;
+ std::unique_ptr<VdexFile> input_vdex_file_;
std::vector<const char*> dex_filenames_;
std::vector<const char*> dex_locations_;
int zip_fd_;
@@ -2787,6 +2850,8 @@
}
}
+ art::MemMap::Init(); // For ZipEntry::ExtractToMemMap, and vdex.
+
// Check early that the result of compilation can be written
if (!dex2oat->OpenFile()) {
return EXIT_FAILURE;
diff --git a/dex2oat/dex2oat_test.cc b/dex2oat/dex2oat_test.cc
index fa32178..714a58c 100644
--- a/dex2oat/dex2oat_test.cc
+++ b/dex2oat/dex2oat_test.cc
@@ -24,6 +24,7 @@
#include "base/logging.h"
#include "base/macros.h"
#include "base/stringprintf.h"
+#include "dex_file-inl.h"
#include "dex2oat_environment_test.h"
#include "oat.h"
#include "oat_file.h"
@@ -551,4 +552,107 @@
RunTest(CompilerFilter::kSpeed, true, { "--very-large-app-threshold=100" });
}
+static const char kDexFileLayoutInputProfile[] = "cHJvADAwMgABAAwAAQABAOqMEeFEZXhOb09hdC5qYXIBAAEA";
+
+static void WriteFileBase64(const char* base64, const char* location) {
+ // Decode base64.
+ CHECK(base64 != nullptr);
+ size_t length;
+ std::unique_ptr<uint8_t[]> bytes(DecodeBase64(base64, &length));
+ CHECK(bytes.get() != nullptr);
+
+ // Write to provided file.
+ std::unique_ptr<File> file(OS::CreateEmptyFile(location));
+ CHECK(file.get() != nullptr);
+ if (!file->WriteFully(bytes.get(), length)) {
+ PLOG(FATAL) << "Failed to write base64 as file";
+ }
+ if (file->FlushCloseOrErase() != 0) {
+ PLOG(FATAL) << "Could not flush and close test file.";
+ }
+}
+
+class Dex2oatLayoutTest : public Dex2oatTest {
+ protected:
+ void CheckFilter(CompilerFilter::Filter input ATTRIBUTE_UNUSED,
+ CompilerFilter::Filter result ATTRIBUTE_UNUSED) OVERRIDE {
+ // Ignore, we'll do our own checks.
+ }
+
+ void RunTest() {
+ std::string dex_location = GetScratchDir() + "/DexNoOat.jar";
+ std::string profile_location = GetScratchDir() + "/primary.prof";
+ std::string odex_location = GetOdexDir() + "/DexOdexNoOat.odex";
+
+ Copy(GetDexSrc2(), dex_location);
+ WriteFileBase64(kDexFileLayoutInputProfile, profile_location.c_str());
+
+ const std::vector<std::string>& extra_args = { "--profile-file=" + profile_location };
+ GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kLayoutProfile, extra_args);
+
+ CheckValidity();
+ ASSERT_TRUE(success_);
+ CheckResult(dex_location, odex_location);
+ }
+ void CheckResult(const std::string& dex_location, const std::string& odex_location) {
+ // Host/target independent checks.
+ std::string error_msg;
+ std::unique_ptr<OatFile> odex_file(OatFile::Open(odex_location.c_str(),
+ odex_location.c_str(),
+ nullptr,
+ nullptr,
+ false,
+ /*low_4gb*/false,
+ dex_location.c_str(),
+ &error_msg));
+ ASSERT_TRUE(odex_file.get() != nullptr) << error_msg;
+
+ const char* location = dex_location.c_str();
+ std::vector<std::unique_ptr<const DexFile>> dex_files;
+ ASSERT_TRUE(DexFile::Open(location, location, true, &error_msg, &dex_files));
+ EXPECT_EQ(dex_files.size(), 1U);
+ std::unique_ptr<const DexFile>& old_dex_file = dex_files[0];
+
+ for (const OatDexFile* oat_dex_file : odex_file->GetOatDexFiles()) {
+ std::unique_ptr<const DexFile> new_dex_file = oat_dex_file->OpenDexFile(&error_msg);
+ ASSERT_TRUE(new_dex_file != nullptr);
+ uint32_t class_def_count = new_dex_file->NumClassDefs();
+ ASSERT_LT(class_def_count, std::numeric_limits<uint16_t>::max());
+ ASSERT_GE(class_def_count, 2U);
+
+ // The new layout swaps the classes at indexes 0 and 1.
+ std::string old_class0 = old_dex_file->PrettyType(old_dex_file->GetClassDef(0).class_idx_);
+ std::string old_class1 = old_dex_file->PrettyType(old_dex_file->GetClassDef(1).class_idx_);
+ std::string new_class0 = new_dex_file->PrettyType(new_dex_file->GetClassDef(0).class_idx_);
+ std::string new_class1 = new_dex_file->PrettyType(new_dex_file->GetClassDef(1).class_idx_);
+ EXPECT_EQ(old_class0, new_class1);
+ EXPECT_EQ(old_class1, new_class0);
+ }
+
+ EXPECT_EQ(odex_file->GetCompilerFilter(), CompilerFilter::kLayoutProfile);
+ }
+
+ // Check whether the dex2oat run was really successful.
+ void CheckValidity() {
+ if (kIsTargetBuild) {
+ CheckTargetValidity();
+ } else {
+ CheckHostValidity();
+ }
+ }
+
+ void CheckTargetValidity() {
+ // TODO: Ignore for now.
+ }
+
+ // On the host, we can get the dex2oat output. Here, look for "dex2oat took."
+ void CheckHostValidity() {
+ EXPECT_NE(output_.find("dex2oat took"), std::string::npos) << output_;
+ }
+ };
+
+TEST_F(Dex2oatLayoutTest, TestLayout) {
+ RunTest();
+}
+
} // namespace art
diff --git a/dexdump/dexdump.cc b/dexdump/dexdump.cc
index 30de28e..03d6227 100644
--- a/dexdump/dexdump.cc
+++ b/dexdump/dexdump.cc
@@ -45,6 +45,7 @@
#include "base/stringprintf.h"
#include "dexdump_cfg.h"
#include "dex_file-inl.h"
+#include "dex_file_types.h"
#include "dex_instruction-inl.h"
namespace art {
@@ -482,7 +483,7 @@
}
case DexFile::kDexAnnotationType: {
const u4 str_idx = static_cast<u4>(readVarWidth(data, arg, false));
- fputs(pDexFile->StringByTypeIdx(str_idx), gOutFile);
+ fputs(pDexFile->StringByTypeIdx(dex::TypeIndex(str_idx)), gOutFile);
break;
}
case DexFile::kDexAnnotationField:
@@ -511,7 +512,7 @@
}
case DexFile::kDexAnnotationAnnotation: {
const u4 type_idx = DecodeUnsignedLeb128(data);
- fputs(pDexFile->StringByTypeIdx(type_idx), gOutFile);
+ fputs(pDexFile->StringByTypeIdx(dex::TypeIndex(type_idx)), gOutFile);
// Decode and display all name=value pairs.
const u4 size = DecodeUnsignedLeb128(data);
for (u4 i = 0; i < size; i++) {
@@ -592,10 +593,10 @@
// General class information.
const DexFile::ClassDef& pClassDef = pDexFile->GetClassDef(idx);
fprintf(gOutFile, "Class #%d header:\n", idx);
- fprintf(gOutFile, "class_idx : %d\n", pClassDef.class_idx_);
+ fprintf(gOutFile, "class_idx : %d\n", pClassDef.class_idx_.index_);
fprintf(gOutFile, "access_flags : %d (0x%04x)\n",
pClassDef.access_flags_, pClassDef.access_flags_);
- fprintf(gOutFile, "superclass_idx : %d\n", pClassDef.superclass_idx_);
+ fprintf(gOutFile, "superclass_idx : %d\n", pClassDef.superclass_idx_.index_);
fprintf(gOutFile, "interfaces_off : %d (0x%06x)\n",
pClassDef.interfaces_off_, pClassDef.interfaces_off_);
fprintf(gOutFile, "source_file_idx : %d\n", pClassDef.source_file_idx_);
@@ -747,9 +748,8 @@
const u4 end = start + pTry->insn_count_;
fprintf(gOutFile, " 0x%04x - 0x%04x\n", start, end);
for (CatchHandlerIterator it(*pCode, *pTry); it.HasNext(); it.Next()) {
- const u2 tidx = it.GetHandlerTypeIndex();
- const char* descriptor =
- (tidx == DexFile::kDexNoIndex16) ? "<any>" : pDexFile->StringByTypeIdx(tidx);
+ const dex::TypeIndex tidx = it.GetHandlerTypeIndex();
+ const char* descriptor = (!tidx.IsValid()) ? "<any>" : pDexFile->StringByTypeIdx(tidx);
fprintf(gOutFile, " %s -> 0x%04x\n", descriptor, it.GetHandlerAddress());
} // for
} // for
@@ -834,7 +834,7 @@
break;
case Instruction::kIndexTypeRef:
if (index < pDexFile->GetHeader().type_ids_size_) {
- const char* tp = pDexFile->StringByTypeIdx(index);
+ const char* tp = pDexFile->StringByTypeIdx(dex::TypeIndex(index));
outSize = snprintf(buf.get(), bufSize, "%s // type@%0*x", tp, width, index);
} else {
outSize = snprintf(buf.get(), bufSize, "<type?> // type@%0*x", width, index);
@@ -1461,7 +1461,7 @@
// General class information.
char* accessStr = createAccessFlagStr(pClassDef.access_flags_, kAccessForClass);
const char* superclassDescriptor;
- if (pClassDef.superclass_idx_ == DexFile::kDexNoIndex16) {
+ if (!pClassDef.superclass_idx_.IsValid()) {
superclassDescriptor = nullptr;
} else {
superclassDescriptor = pDexFile->StringByTypeIdx(pClassDef.superclass_idx_);
diff --git a/dexlayout/Android.bp b/dexlayout/Android.bp
index b9266f7..9ee9ebd 100644
--- a/dexlayout/Android.bp
+++ b/dexlayout/Android.bp
@@ -12,28 +12,46 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-art_cc_binary {
- name: "dexlayout",
+art_cc_defaults {
+ name: "libart-dexlayout-defaults",
host_supported: true,
srcs: [
- "dexlayout_main.cc",
"dexlayout.cc",
"dex_ir.cc",
"dex_ir_builder.cc",
"dex_visualize.cc",
"dex_writer.cc",
],
+ export_include_dirs: ["."],
+ shared_libs: ["libbase"],
+ static_libs: ["libz"],
+}
+
+art_cc_library {
+ name: "libart-dexlayout",
+ defaults: ["libart-dexlayout-defaults"],
+ shared_libs: ["libart"],
+}
+
+art_cc_library {
+ name: "libartd-dexlayout",
+ defaults: ["libart-dexlayout-defaults"],
+ shared_libs: ["libartd"],
+}
+
+art_cc_binary {
+ name: "dexlayout",
+ host_supported: true,
+ srcs: ["dexlayout_main.cc"],
cflags: ["-Wall"],
shared_libs: [
"libart",
- "libbase",
+ "libart-dexlayout",
],
}
art_cc_test {
name: "art_dexlayout_tests",
- defaults: [
- "art_gtest_defaults",
- ],
+ defaults: ["art_gtest_defaults"],
srcs: ["dexlayout_test.cc"],
}
diff --git a/dexlayout/dex_ir.cc b/dexlayout/dex_ir.cc
index c3c763f..fe2bcce 100644
--- a/dexlayout/dex_ir.cc
+++ b/dexlayout/dex_ir.cc
@@ -56,6 +56,36 @@
entry.end_address_, entry.reg_)));
}
+static uint32_t GetCodeItemSize(const DexFile& dex_file, const DexFile::CodeItem& disk_code_item) {
+ uintptr_t code_item_start = reinterpret_cast<uintptr_t>(&disk_code_item);
+ uint32_t insns_size = disk_code_item.insns_size_in_code_units_;
+ uint32_t tries_size = disk_code_item.tries_size_;
+ if (tries_size == 0) {
+ uintptr_t insns_end = reinterpret_cast<uintptr_t>(&disk_code_item.insns_[insns_size]);
+ return insns_end - code_item_start;
+ } else {
+ uint32_t last_handler_off = 0;
+ for (uint32_t i = 0; i < tries_size; ++i) {
+ // Iterate over the try items to find the last catch handler.
+ const DexFile::TryItem* disk_try_item = dex_file.GetTryItems(disk_code_item, i);
+ uint16_t handler_off = disk_try_item->handler_off_;
+ if (handler_off > last_handler_off) {
+ last_handler_off = handler_off;
+ }
+ }
+ // Decode the final handler to see where it ends.
+ const uint8_t* handler_data = DexFile::GetCatchHandlerData(disk_code_item, last_handler_off);
+ int32_t uleb128_count = DecodeSignedLeb128(&handler_data) * 2;
+ if (uleb128_count <= 0) {
+ uleb128_count = -uleb128_count + 1;
+ }
+ for (int32_t i = 0; i < uleb128_count; ++i) {
+ DecodeUnsignedLeb128(&handler_data);
+ }
+ return reinterpret_cast<uintptr_t>(handler_data) - code_item_start;
+ }
+}
+
static uint32_t GetDebugInfoStreamSize(const uint8_t* debug_info_stream) {
const uint8_t* stream = debug_info_stream;
DecodeUnsignedLeb128(&stream); // line_start
@@ -319,7 +349,7 @@
}
void Collections::CreateTypeId(const DexFile& dex_file, uint32_t i) {
- const DexFile::TypeId& disk_type_id = dex_file.GetTypeId(i);
+ const DexFile::TypeId& disk_type_id = dex_file.GetTypeId(dex::TypeIndex(i));
TypeId* type_id = new TypeId(GetStringId(disk_type_id.descriptor_idx_));
type_ids_.AddIndexedItem(type_id, TypeIdsOffset() + i * TypeId::ItemSize(), i);
}
@@ -330,22 +360,22 @@
TypeList* parameter_type_list = CreateTypeList(type_list, disk_proto_id.parameters_off_);
ProtoId* proto_id = new ProtoId(GetStringId(disk_proto_id.shorty_idx_),
- GetTypeId(disk_proto_id.return_type_idx_),
+ GetTypeId(disk_proto_id.return_type_idx_.index_),
parameter_type_list);
proto_ids_.AddIndexedItem(proto_id, ProtoIdsOffset() + i * ProtoId::ItemSize(), i);
}
void Collections::CreateFieldId(const DexFile& dex_file, uint32_t i) {
const DexFile::FieldId& disk_field_id = dex_file.GetFieldId(i);
- FieldId* field_id = new FieldId(GetTypeId(disk_field_id.class_idx_),
- GetTypeId(disk_field_id.type_idx_),
+ FieldId* field_id = new FieldId(GetTypeId(disk_field_id.class_idx_.index_),
+ GetTypeId(disk_field_id.type_idx_.index_),
GetStringId(disk_field_id.name_idx_));
field_ids_.AddIndexedItem(field_id, FieldIdsOffset() + i * FieldId::ItemSize(), i);
}
void Collections::CreateMethodId(const DexFile& dex_file, uint32_t i) {
const DexFile::MethodId& disk_method_id = dex_file.GetMethodId(i);
- MethodId* method_id = new MethodId(GetTypeId(disk_method_id.class_idx_),
+ MethodId* method_id = new MethodId(GetTypeId(disk_method_id.class_idx_.index_),
GetProtoId(disk_method_id.proto_idx_),
GetStringId(disk_method_id.name_idx_));
method_ids_.AddIndexedItem(method_id, MethodIdsOffset() + i * MethodId::ItemSize(), i);
@@ -353,9 +383,9 @@
void Collections::CreateClassDef(const DexFile& dex_file, uint32_t i) {
const DexFile::ClassDef& disk_class_def = dex_file.GetClassDef(i);
- const TypeId* class_type = GetTypeId(disk_class_def.class_idx_);
+ const TypeId* class_type = GetTypeId(disk_class_def.class_idx_.index_);
uint32_t access_flags = disk_class_def.access_flags_;
- const TypeId* superclass = GetTypeIdOrNullPtr(disk_class_def.superclass_idx_);
+ const TypeId* superclass = GetTypeIdOrNullPtr(disk_class_def.superclass_idx_.index_);
const DexFile::TypeList* type_list = dex_file.GetInterfacesList(disk_class_def);
TypeList* interfaces_type_list = CreateTypeList(type_list, disk_class_def.interfaces_off_);
@@ -384,16 +414,14 @@
if (dex_type_list == nullptr) {
return nullptr;
}
- // TODO: Create more efficient lookup for existing type lists.
- for (std::unique_ptr<TypeList>& type_list : TypeLists()) {
- if (type_list->GetOffset() == offset) {
- return type_list.get();
- }
+ auto found_type_list = TypeLists().find(offset);
+ if (found_type_list != TypeLists().end()) {
+ return found_type_list->second.get();
}
TypeIdVector* type_vector = new TypeIdVector();
uint32_t size = dex_type_list->Size();
for (uint32_t index = 0; index < size; ++index) {
- type_vector->push_back(GetTypeId(dex_type_list->GetTypeItem(index).type_idx_));
+ type_vector->push_back(GetTypeId(dex_type_list->GetTypeItem(index).type_idx_.index_));
}
TypeList* new_type_list = new TypeList(type_vector);
type_lists_.AddItem(new_type_list, offset);
@@ -404,10 +432,9 @@
if (static_data == nullptr) {
return nullptr;
}
- for (std::unique_ptr<EncodedArrayItem>& existing_array_item : EncodedArrayItems()) {
- if (existing_array_item->GetOffset() == offset) {
- return existing_array_item.get();
- }
+ auto found_encoded_array_item = EncodedArrayItems().find(offset);
+ if (found_encoded_array_item != EncodedArrayItems().end()) {
+ return found_encoded_array_item->second.get();
}
uint32_t size = DecodeUnsignedLeb128(&static_data);
EncodedValueVector* values = new EncodedValueVector();
@@ -422,10 +449,9 @@
AnnotationItem* Collections::CreateAnnotationItem(const DexFile::AnnotationItem* annotation,
uint32_t offset) {
- for (std::unique_ptr<AnnotationItem>& existing_annotation_item : AnnotationItems()) {
- if (existing_annotation_item->GetOffset() == offset) {
- return existing_annotation_item.get();
- }
+ auto found_annotation_item = AnnotationItems().find(offset);
+ if (found_annotation_item != AnnotationItems().end()) {
+ return found_annotation_item->second.get();
}
uint8_t visibility = annotation->visibility_;
const uint8_t* annotation_data = annotation->annotation_;
@@ -444,10 +470,9 @@
if (disk_annotations_item.size_ == 0 && offset == 0) {
return nullptr;
}
- for (std::unique_ptr<AnnotationSetItem>& existing_anno_set_item : AnnotationSetItems()) {
- if (existing_anno_set_item->GetOffset() == offset) {
- return existing_anno_set_item.get();
- }
+ auto found_anno_set_item = AnnotationSetItems().find(offset);
+ if (found_anno_set_item != AnnotationSetItems().end()) {
+ return found_anno_set_item->second.get();
}
std::vector<AnnotationItem*>* items = new std::vector<AnnotationItem*>();
for (uint32_t i = 0; i < disk_annotations_item.size_; ++i) {
@@ -467,10 +492,9 @@
AnnotationsDirectoryItem* Collections::CreateAnnotationsDirectoryItem(const DexFile& dex_file,
const DexFile::AnnotationsDirectoryItem* disk_annotations_item, uint32_t offset) {
- for (std::unique_ptr<AnnotationsDirectoryItem>& anno_dir_item : AnnotationsDirectoryItems()) {
- if (anno_dir_item->GetOffset() == offset) {
- return anno_dir_item.get();
- }
+ auto found_anno_dir_item = AnnotationsDirectoryItems().find(offset);
+ if (found_anno_dir_item != AnnotationsDirectoryItems().end()) {
+ return found_anno_dir_item->second.get();
}
const DexFile::AnnotationSetItem* class_set_item =
dex_file.GetClassAnnotationSet(disk_annotations_item);
@@ -535,11 +559,9 @@
const DexFile& dex_file, MethodId* method_id,
const DexFile::AnnotationSetRefList* annotation_set_ref_list, uint32_t offset) {
AnnotationSetRefList* set_ref_list = nullptr;
- for (std::unique_ptr<AnnotationSetRefList>& existing_set_ref_list : AnnotationSetRefLists()) {
- if (existing_set_ref_list->GetOffset() == offset) {
- set_ref_list = existing_set_ref_list.get();
- break;
- }
+ auto found_set_ref_list = AnnotationSetRefLists().find(offset);
+ if (found_set_ref_list != AnnotationSetRefLists().end()) {
+ set_ref_list = found_set_ref_list->second.get();
}
if (set_ref_list == nullptr) {
std::vector<AnnotationSetItem*>* annotations = new std::vector<AnnotationSetItem*>();
@@ -597,8 +619,8 @@
bool catch_all = false;
TypeAddrPairVector* addr_pairs = new TypeAddrPairVector();
for (CatchHandlerIterator it(disk_code_item, *disk_try_item); it.HasNext(); it.Next()) {
- const uint16_t type_index = it.GetHandlerTypeIndex();
- const TypeId* type_id = GetTypeIdOrNullPtr(type_index);
+ const dex::TypeIndex type_index = it.GetHandlerTypeIndex();
+ const TypeId* type_id = GetTypeIdOrNullPtr(type_index.index_);
catch_all |= type_id == nullptr;
addr_pairs->push_back(std::unique_ptr<const TypeAddrPair>(
new TypeAddrPair(type_id, it.GetHandlerAddress())));
@@ -610,9 +632,10 @@
tries->push_back(std::unique_ptr<const TryItem>(try_item));
}
}
- // TODO: Calculate the size of the code item.
+ uint32_t size = GetCodeItemSize(dex_file, disk_code_item);
CodeItem* code_item = new CodeItem(
registers_size, ins_size, outs_size, debug_info, insns_size, insns, tries, handler_list);
+ code_item->SetSize(size);
code_items_.AddItem(code_item, offset);
// Add "fixup" references to types, strings, methods, and fields.
// This is temporary, as we will probably want more detailed parsing of the
@@ -690,8 +713,8 @@
virtual_methods->push_back(
std::unique_ptr<MethodItem>(GenerateMethodItem(dex_file, cdii)));
}
- // TODO: Calculate the size of the class data.
class_data = new ClassData(static_fields, instance_fields, direct_methods, virtual_methods);
+ class_data->SetSize(cdii.EndDataPointer() - encoded_data);
class_datas_.AddItem(class_data, offset);
}
return class_data;
diff --git a/dexlayout/dex_ir.h b/dexlayout/dex_ir.h
index 38eb0b1..a2d1190 100644
--- a/dexlayout/dex_ir.h
+++ b/dexlayout/dex_ir.h
@@ -19,6 +19,7 @@
#ifndef ART_DEXLAYOUT_DEX_IR_H_
#define ART_DEXLAYOUT_DEX_IR_H_
+#include <map>
#include <vector>
#include <stdint.h>
@@ -98,34 +99,52 @@
};
// Collections become owners of the objects added by moving them into unique pointers.
-template<class T> class CollectionWithOffset {
+template<class T> class CollectionBase {
public:
- CollectionWithOffset() = default;
- std::vector<std::unique_ptr<T>>& Collection() { return collection_; }
- // Read-time support methods
- void AddItem(T* object, uint32_t offset) {
- object->SetOffset(offset);
- collection_.push_back(std::unique_ptr<T>(object));
- }
+ CollectionBase() = default;
+
+ uint32_t GetOffset() const { return offset_; }
+ void SetOffset(uint32_t new_offset) { offset_ = new_offset; }
+
+ private:
+ uint32_t offset_ = 0;
+
+ DISALLOW_COPY_AND_ASSIGN(CollectionBase);
+};
+
+template<class T> class CollectionVector : public CollectionBase<T> {
+ public:
+ CollectionVector() = default;
+
void AddIndexedItem(T* object, uint32_t offset, uint32_t index) {
object->SetOffset(offset);
object->SetIndex(index);
collection_.push_back(std::unique_ptr<T>(object));
}
- // Ordinary object insertion into collection.
- void Insert(T object ATTRIBUTE_UNUSED) {
- // TODO(sehr): add ordered insertion support.
- UNIMPLEMENTED(FATAL) << "Insertion not ready";
- }
- uint32_t GetOffset() const { return offset_; }
- void SetOffset(uint32_t new_offset) { offset_ = new_offset; }
uint32_t Size() const { return collection_.size(); }
+ std::vector<std::unique_ptr<T>>& Collection() { return collection_; }
private:
std::vector<std::unique_ptr<T>> collection_;
- uint32_t offset_ = 0;
- DISALLOW_COPY_AND_ASSIGN(CollectionWithOffset);
+ DISALLOW_COPY_AND_ASSIGN(CollectionVector);
+};
+
+template<class T> class CollectionMap : public CollectionBase<T> {
+ public:
+ CollectionMap() = default;
+
+ void AddItem(T* object, uint32_t offset) {
+ object->SetOffset(offset);
+ collection_.emplace(offset, std::unique_ptr<T>(object));
+ }
+ uint32_t Size() const { return collection_.size(); }
+ std::map<uint32_t, std::unique_ptr<T>>& Collection() { return collection_; }
+
+ private:
+ std::map<uint32_t, std::unique_ptr<T>> collection_;
+
+ DISALLOW_COPY_AND_ASSIGN(CollectionMap);
};
class Collections {
@@ -138,22 +157,23 @@
std::vector<std::unique_ptr<FieldId>>& FieldIds() { return field_ids_.Collection(); }
std::vector<std::unique_ptr<MethodId>>& MethodIds() { return method_ids_.Collection(); }
std::vector<std::unique_ptr<ClassDef>>& ClassDefs() { return class_defs_.Collection(); }
- std::vector<std::unique_ptr<StringData>>& StringDatas() { return string_datas_.Collection(); }
- std::vector<std::unique_ptr<TypeList>>& TypeLists() { return type_lists_.Collection(); }
- std::vector<std::unique_ptr<EncodedArrayItem>>& EncodedArrayItems()
+ std::map<uint32_t, std::unique_ptr<StringData>>& StringDatas()
+ { return string_datas_.Collection(); }
+ std::map<uint32_t, std::unique_ptr<TypeList>>& TypeLists() { return type_lists_.Collection(); }
+ std::map<uint32_t, std::unique_ptr<EncodedArrayItem>>& EncodedArrayItems()
{ return encoded_array_items_.Collection(); }
- std::vector<std::unique_ptr<AnnotationItem>>& AnnotationItems()
+ std::map<uint32_t, std::unique_ptr<AnnotationItem>>& AnnotationItems()
{ return annotation_items_.Collection(); }
- std::vector<std::unique_ptr<AnnotationSetItem>>& AnnotationSetItems()
+ std::map<uint32_t, std::unique_ptr<AnnotationSetItem>>& AnnotationSetItems()
{ return annotation_set_items_.Collection(); }
- std::vector<std::unique_ptr<AnnotationSetRefList>>& AnnotationSetRefLists()
+ std::map<uint32_t, std::unique_ptr<AnnotationSetRefList>>& AnnotationSetRefLists()
{ return annotation_set_ref_lists_.Collection(); }
- std::vector<std::unique_ptr<AnnotationsDirectoryItem>>& AnnotationsDirectoryItems()
+ std::map<uint32_t, std::unique_ptr<AnnotationsDirectoryItem>>& AnnotationsDirectoryItems()
{ return annotations_directory_items_.Collection(); }
- std::vector<std::unique_ptr<DebugInfoItem>>& DebugInfoItems()
+ std::map<uint32_t, std::unique_ptr<DebugInfoItem>>& DebugInfoItems()
{ return debug_info_items_.Collection(); }
- std::vector<std::unique_ptr<CodeItem>>& CodeItems() { return code_items_.Collection(); }
- std::vector<std::unique_ptr<ClassData>>& ClassDatas() { return class_datas_.Collection(); }
+ std::map<uint32_t, std::unique_ptr<CodeItem>>& CodeItems() { return code_items_.Collection(); }
+ std::map<uint32_t, std::unique_ptr<ClassData>>& ClassDatas() { return class_datas_.Collection(); }
void CreateStringId(const DexFile& dex_file, uint32_t i);
void CreateTypeId(const DexFile& dex_file, uint32_t i);
@@ -204,7 +224,7 @@
uint32_t DebugInfoItemsOffset() const { return debug_info_items_.GetOffset(); }
uint32_t CodeItemsOffset() const { return code_items_.GetOffset(); }
uint32_t ClassDatasOffset() const { return class_datas_.GetOffset(); }
- uint32_t MapItemOffset() const { return map_item_offset_; }
+ uint32_t MapListOffset() const { return map_list_offset_; }
void SetStringIdsOffset(uint32_t new_offset) { string_ids_.SetOffset(new_offset); }
void SetTypeIdsOffset(uint32_t new_offset) { type_ids_.SetOffset(new_offset); }
@@ -226,7 +246,7 @@
void SetDebugInfoItemsOffset(uint32_t new_offset) { debug_info_items_.SetOffset(new_offset); }
void SetCodeItemsOffset(uint32_t new_offset) { code_items_.SetOffset(new_offset); }
void SetClassDatasOffset(uint32_t new_offset) { class_datas_.SetOffset(new_offset); }
- void SetMapItemOffset(uint32_t new_offset) { map_item_offset_ = new_offset; }
+ void SetMapListOffset(uint32_t new_offset) { map_list_offset_ = new_offset; }
uint32_t StringIdsSize() const { return string_ids_.Size(); }
uint32_t TypeIdsSize() const { return type_ids_.Size(); }
@@ -254,25 +274,25 @@
const DexFile::AnnotationSetRefList* annotation_set_ref_list, uint32_t offset);
MethodItem* GenerateMethodItem(const DexFile& dex_file, ClassDataItemIterator& cdii);
- CollectionWithOffset<StringId> string_ids_;
- CollectionWithOffset<TypeId> type_ids_;
- CollectionWithOffset<ProtoId> proto_ids_;
- CollectionWithOffset<FieldId> field_ids_;
- CollectionWithOffset<MethodId> method_ids_;
- CollectionWithOffset<ClassDef> class_defs_;
+ CollectionVector<StringId> string_ids_;
+ CollectionVector<TypeId> type_ids_;
+ CollectionVector<ProtoId> proto_ids_;
+ CollectionVector<FieldId> field_ids_;
+ CollectionVector<MethodId> method_ids_;
+ CollectionVector<ClassDef> class_defs_;
- CollectionWithOffset<StringData> string_datas_;
- CollectionWithOffset<TypeList> type_lists_;
- CollectionWithOffset<EncodedArrayItem> encoded_array_items_;
- CollectionWithOffset<AnnotationItem> annotation_items_;
- CollectionWithOffset<AnnotationSetItem> annotation_set_items_;
- CollectionWithOffset<AnnotationSetRefList> annotation_set_ref_lists_;
- CollectionWithOffset<AnnotationsDirectoryItem> annotations_directory_items_;
- CollectionWithOffset<DebugInfoItem> debug_info_items_;
- CollectionWithOffset<CodeItem> code_items_;
- CollectionWithOffset<ClassData> class_datas_;
+ CollectionMap<StringData> string_datas_;
+ CollectionMap<TypeList> type_lists_;
+ CollectionMap<EncodedArrayItem> encoded_array_items_;
+ CollectionMap<AnnotationItem> annotation_items_;
+ CollectionMap<AnnotationSetItem> annotation_set_items_;
+ CollectionMap<AnnotationSetRefList> annotation_set_ref_lists_;
+ CollectionMap<AnnotationsDirectoryItem> annotations_directory_items_;
+ CollectionMap<DebugInfoItem> debug_info_items_;
+ CollectionMap<CodeItem> code_items_;
+ CollectionMap<ClassData> class_datas_;
- uint32_t map_item_offset_ = 0;
+ uint32_t map_list_offset_ = 0;
DISALLOW_COPY_AND_ASSIGN(Collections);
};
@@ -539,20 +559,20 @@
class MethodItem : public Item {
public:
- MethodItem(uint32_t access_flags, const MethodId* method_id, const CodeItem* code)
+ MethodItem(uint32_t access_flags, const MethodId* method_id, CodeItem* code)
: access_flags_(access_flags), method_id_(method_id), code_(code) { }
~MethodItem() OVERRIDE { }
uint32_t GetAccessFlags() const { return access_flags_; }
const MethodId* GetMethodId() const { return method_id_; }
- const CodeItem* GetCodeItem() const { return code_; }
+ CodeItem* GetCodeItem() { return code_; }
void Accept(AbstractDispatcher* dispatch) { dispatch->Dispatch(this); }
private:
uint32_t access_flags_;
const MethodId* method_id_;
- const CodeItem* code_; // This can be nullptr.
+ CodeItem* code_; // This can be nullptr.
DISALLOW_COPY_AND_ASSIGN(MethodItem);
};
diff --git a/dexlayout/dex_ir_builder.cc b/dexlayout/dex_ir_builder.cc
index 68ff2a2..d0c5bf9 100644
--- a/dexlayout/dex_ir_builder.cc
+++ b/dexlayout/dex_ir_builder.cc
@@ -71,7 +71,7 @@
collections.CreateClassDef(dex_file, i);
}
// MapItem.
- collections.SetMapItemOffset(disk_header.map_off_);
+ collections.SetMapListOffset(disk_header.map_off_);
CheckAndSetRemainingOffsets(dex_file, &collections);
diff --git a/dexlayout/dex_visualize.cc b/dexlayout/dex_visualize.cc
index bc9ca6d..02274b2 100644
--- a/dexlayout/dex_visualize.cc
+++ b/dexlayout/dex_visualize.cc
@@ -263,11 +263,13 @@
DumpStringId(method_id->Name(), class_index);
}
- void DumpMethodItem(const dex_ir::MethodItem* method, const DexFile* dex_file, int class_index) {
- if (profile_info_ != nullptr) {
+ void DumpMethodItem(dex_ir::MethodItem* method,
+ const DexFile* dex_file,
+ int class_index,
+ ProfileCompilationInfo* profile_info) {
+ if (profile_info != nullptr) {
uint32_t method_idx = method->GetMethodId()->GetIndex();
- MethodReference mr(dex_file, method_idx);
- if (!profile_info_->ContainsMethod(mr)) {
+ if (!profile_info->ContainsMethod(MethodReference(dex_file, method_idx))) {
return;
}
}
@@ -344,13 +346,17 @@
* Dumps a gnuplot data file showing the parts of the dex_file that belong to each class.
* If profiling information is present, it dumps only those classes that are marked as hot.
*/
-void VisualizeDexLayout(dex_ir::Header* header, const DexFile* dex_file, size_t dex_file_index) {
+void VisualizeDexLayout(dex_ir::Header* header,
+ const DexFile* dex_file,
+ size_t dex_file_index,
+ ProfileCompilationInfo* profile_info) {
std::unique_ptr<Dumper> dumper(new Dumper(header->GetCollections(), dex_file_index));
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)) {
+ dex::TypeIndex type_idx(class_def->ClassType()->GetIndex());
+ if (profile_info != nullptr && !profile_info->ContainsClass(*dex_file, type_idx)) {
continue;
}
dumper->DumpAddressRange(class_def, class_index);
@@ -383,12 +389,12 @@
}
if (class_data->DirectMethods()) {
for (auto& method_item : *class_data->DirectMethods()) {
- dumper->DumpMethodItem(method_item.get(), dex_file, class_index);
+ dumper->DumpMethodItem(method_item.get(), dex_file, class_index, profile_info);
}
}
if (class_data->VirtualMethods()) {
for (auto& method_item : *class_data->VirtualMethods()) {
- dumper->DumpMethodItem(method_item.get(), dex_file, class_index);
+ dumper->DumpMethodItem(method_item.get(), dex_file, class_index, profile_info);
}
}
}
diff --git a/dexlayout/dex_visualize.h b/dexlayout/dex_visualize.h
index b1d2ed7..09f8306 100644
--- a/dexlayout/dex_visualize.h
+++ b/dexlayout/dex_visualize.h
@@ -28,11 +28,15 @@
namespace art {
class DexFile;
+class ProfileCompilationInfo;
namespace dex_ir {
class Header;
} // namespace dex_ir
-void VisualizeDexLayout(dex_ir::Header* header, const DexFile* dex_file, size_t dex_file_index);
+void VisualizeDexLayout(dex_ir::Header* header,
+ const DexFile* dex_file,
+ size_t dex_file_index,
+ ProfileCompilationInfo* profile_info);
} // namespace art
diff --git a/dexlayout/dex_writer.cc b/dexlayout/dex_writer.cc
index dba5da0..7ffa38b 100644
--- a/dexlayout/dex_writer.cc
+++ b/dexlayout/dex_writer.cc
@@ -104,7 +104,9 @@
}
size_t DexWriter::Write(const void* buffer, size_t length, size_t offset) {
- return dex_file_->PwriteFully(buffer, length, offset) ? length : 0;
+ DCHECK_LE(offset + length, mem_map_->Size());
+ memcpy(mem_map_->Begin() + offset, buffer, length);
+ return length;
}
size_t DexWriter::WriteSleb128(uint32_t value, size_t offset) {
@@ -236,12 +238,13 @@
void DexWriter::WriteStrings() {
uint32_t string_data_off[1];
- for (std::unique_ptr<dex_ir::StringId>& string_id : header_.GetCollections().StringIds()) {
+ for (std::unique_ptr<dex_ir::StringId>& string_id : header_->GetCollections().StringIds()) {
string_data_off[0] = string_id->DataItem()->GetOffset();
Write(string_data_off, string_id->GetSize(), string_id->GetOffset());
}
- for (std::unique_ptr<dex_ir::StringData>& string_data : header_.GetCollections().StringDatas()) {
+ for (auto& string_data_pair : header_->GetCollections().StringDatas()) {
+ std::unique_ptr<dex_ir::StringData>& string_data = string_data_pair.second;
uint32_t offset = string_data->GetOffset();
offset += WriteUleb128(CountModifiedUtf8Chars(string_data->Data()), offset);
Write(string_data->Data(), strlen(string_data->Data()), offset);
@@ -250,7 +253,7 @@
void DexWriter::WriteTypes() {
uint32_t descriptor_idx[1];
- for (std::unique_ptr<dex_ir::TypeId>& type_id : header_.GetCollections().TypeIds()) {
+ for (std::unique_ptr<dex_ir::TypeId>& type_id : header_->GetCollections().TypeIds()) {
descriptor_idx[0] = type_id->GetStringId()->GetIndex();
Write(descriptor_idx, type_id->GetSize(), type_id->GetOffset());
}
@@ -259,7 +262,8 @@
void DexWriter::WriteTypeLists() {
uint32_t size[1];
uint16_t list[1];
- for (std::unique_ptr<dex_ir::TypeList>& type_list : header_.GetCollections().TypeLists()) {
+ for (auto& type_list_pair : header_->GetCollections().TypeLists()) {
+ std::unique_ptr<dex_ir::TypeList>& type_list = type_list_pair.second;
size[0] = type_list->GetTypeList()->size();
uint32_t offset = type_list->GetOffset();
offset += Write(size, sizeof(uint32_t), offset);
@@ -272,7 +276,7 @@
void DexWriter::WriteProtos() {
uint32_t buffer[3];
- for (std::unique_ptr<dex_ir::ProtoId>& proto_id : header_.GetCollections().ProtoIds()) {
+ for (std::unique_ptr<dex_ir::ProtoId>& proto_id : header_->GetCollections().ProtoIds()) {
buffer[0] = proto_id->Shorty()->GetIndex();
buffer[1] = proto_id->ReturnType()->GetIndex();
buffer[2] = proto_id->Parameters() == nullptr ? 0 : proto_id->Parameters()->GetOffset();
@@ -282,7 +286,7 @@
void DexWriter::WriteFields() {
uint16_t buffer[4];
- for (std::unique_ptr<dex_ir::FieldId>& field_id : header_.GetCollections().FieldIds()) {
+ for (std::unique_ptr<dex_ir::FieldId>& field_id : header_->GetCollections().FieldIds()) {
buffer[0] = field_id->Class()->GetIndex();
buffer[1] = field_id->Type()->GetIndex();
buffer[2] = field_id->Name()->GetIndex();
@@ -293,7 +297,7 @@
void DexWriter::WriteMethods() {
uint16_t buffer[4];
- for (std::unique_ptr<dex_ir::MethodId>& method_id : header_.GetCollections().MethodIds()) {
+ for (std::unique_ptr<dex_ir::MethodId>& method_id : header_->GetCollections().MethodIds()) {
buffer[0] = method_id->Class()->GetIndex();
buffer[1] = method_id->Proto()->GetIndex();
buffer[2] = method_id->Name()->GetIndex();
@@ -303,16 +307,16 @@
}
void DexWriter::WriteEncodedArrays() {
- for (std::unique_ptr<dex_ir::EncodedArrayItem>& encoded_array :
- header_.GetCollections().EncodedArrayItems()) {
+ for (auto& encoded_array_pair : header_->GetCollections().EncodedArrayItems()) {
+ std::unique_ptr<dex_ir::EncodedArrayItem>& encoded_array = encoded_array_pair.second;
WriteEncodedArray(encoded_array->GetEncodedValues(), encoded_array->GetOffset());
}
}
void DexWriter::WriteAnnotations() {
uint8_t visibility[1];
- for (std::unique_ptr<dex_ir::AnnotationItem>& annotation :
- header_.GetCollections().AnnotationItems()) {
+ for (auto& annotation_pair : header_->GetCollections().AnnotationItems()) {
+ std::unique_ptr<dex_ir::AnnotationItem>& annotation = annotation_pair.second;
visibility[0] = annotation->GetVisibility();
size_t offset = annotation->GetOffset();
offset += Write(visibility, sizeof(uint8_t), offset);
@@ -323,8 +327,8 @@
void DexWriter::WriteAnnotationSets() {
uint32_t size[1];
uint32_t annotation_off[1];
- for (std::unique_ptr<dex_ir::AnnotationSetItem>& annotation_set :
- header_.GetCollections().AnnotationSetItems()) {
+ for (auto& annotation_set_pair : header_->GetCollections().AnnotationSetItems()) {
+ std::unique_ptr<dex_ir::AnnotationSetItem>& annotation_set = annotation_set_pair.second;
size[0] = annotation_set->GetItems()->size();
size_t offset = annotation_set->GetOffset();
offset += Write(size, sizeof(uint32_t), offset);
@@ -338,8 +342,8 @@
void DexWriter::WriteAnnotationSetRefs() {
uint32_t size[1];
uint32_t annotations_off[1];
- for (std::unique_ptr<dex_ir::AnnotationSetRefList>& annotation_set_ref :
- header_.GetCollections().AnnotationSetRefLists()) {
+ for (auto& anno_set_ref_pair : header_->GetCollections().AnnotationSetRefLists()) {
+ std::unique_ptr<dex_ir::AnnotationSetRefList>& annotation_set_ref = anno_set_ref_pair.second;
size[0] = annotation_set_ref->GetItems()->size();
size_t offset = annotation_set_ref->GetOffset();
offset += Write(size, sizeof(uint32_t), offset);
@@ -353,8 +357,9 @@
void DexWriter::WriteAnnotationsDirectories() {
uint32_t directory_buffer[4];
uint32_t annotation_buffer[2];
- for (std::unique_ptr<dex_ir::AnnotationsDirectoryItem>& annotations_directory :
- header_.GetCollections().AnnotationsDirectoryItems()) {
+ for (auto& annotations_directory_pair : header_->GetCollections().AnnotationsDirectoryItems()) {
+ std::unique_ptr<dex_ir::AnnotationsDirectoryItem>& annotations_directory =
+ annotations_directory_pair.second;
directory_buffer[0] = annotations_directory->GetClassAnnotation() == nullptr ? 0 :
annotations_directory->GetClassAnnotation()->GetOffset();
directory_buffer[1] = annotations_directory->GetFieldAnnotations() == nullptr ? 0 :
@@ -393,15 +398,17 @@
}
void DexWriter::WriteDebugInfoItems() {
- for (std::unique_ptr<dex_ir::DebugInfoItem>& info : header_.GetCollections().DebugInfoItems()) {
- Write(info->GetDebugInfo(), info->GetDebugInfoSize(), info->GetOffset());
+ for (auto& debug_info_pair : header_->GetCollections().DebugInfoItems()) {
+ std::unique_ptr<dex_ir::DebugInfoItem>& debug_info = debug_info_pair.second;
+ Write(debug_info->GetDebugInfo(), debug_info->GetDebugInfoSize(), debug_info->GetOffset());
}
}
void DexWriter::WriteCodeItems() {
uint16_t uint16_buffer[4];
uint32_t uint32_buffer[2];
- for (std::unique_ptr<dex_ir::CodeItem>& code_item : header_.GetCollections().CodeItems()) {
+ for (auto& code_item_pair : header_->GetCollections().CodeItems()) {
+ std::unique_ptr<dex_ir::CodeItem>& code_item = code_item_pair.second;
uint16_buffer[0] = code_item->RegistersSize();
uint16_buffer[1] = code_item->InsSize();
uint16_buffer[2] = code_item->OutsSize();
@@ -446,7 +453,7 @@
void DexWriter::WriteClasses() {
uint32_t class_def_buffer[8];
- for (std::unique_ptr<dex_ir::ClassDef>& class_def : header_.GetCollections().ClassDefs()) {
+ for (std::unique_ptr<dex_ir::ClassDef>& class_def : header_->GetCollections().ClassDefs()) {
class_def_buffer[0] = class_def->ClassType()->GetIndex();
class_def_buffer[1] = class_def->GetAccessFlags();
class_def_buffer[2] = class_def->Superclass() == nullptr ? DexFile::kDexNoIndex :
@@ -464,7 +471,8 @@
Write(class_def_buffer, class_def->GetSize(), offset);
}
- for (std::unique_ptr<dex_ir::ClassData>& class_data : header_.GetCollections().ClassDatas()) {
+ for (auto& class_data_pair : header_->GetCollections().ClassDatas()) {
+ std::unique_ptr<dex_ir::ClassData>& class_data = class_data_pair.second;
size_t offset = class_data->GetOffset();
offset += WriteUleb128(class_data->StaticFields()->size(), offset);
offset += WriteUleb128(class_data->InstanceFields()->size(), offset);
@@ -491,7 +499,7 @@
};
void DexWriter::WriteMapItem() {
- dex_ir::Collections& collection = header_.GetCollections();
+ dex_ir::Collections& collection = header_->GetCollections();
std::priority_queue<MapItemContainer> queue;
// Header and index section.
@@ -522,7 +530,7 @@
}
// Data section.
- queue.push(MapItemContainer(DexFile::kDexTypeMapList, 1, collection.MapItemOffset()));
+ queue.push(MapItemContainer(DexFile::kDexTypeMapList, 1, collection.MapListOffset()));
if (collection.TypeListsSize() != 0) {
queue.push(MapItemContainer(DexFile::kDexTypeTypeList, collection.TypeListsSize(),
collection.TypeListsOffset()));
@@ -564,7 +572,7 @@
collection.AnnotationsDirectoryItemsSize(), collection.AnnotationsDirectoryItemsOffset()));
}
- uint32_t offset = collection.MapItemOffset();
+ uint32_t offset = collection.MapListOffset();
uint16_t uint16_buffer[2];
uint32_t uint32_buffer[2];
uint16_buffer[1] = 0;
@@ -583,19 +591,19 @@
void DexWriter::WriteHeader() {
uint32_t buffer[20];
- dex_ir::Collections& collections = header_.GetCollections();
+ dex_ir::Collections& collections = header_->GetCollections();
size_t offset = 0;
- offset += Write(header_.Magic(), 8 * sizeof(uint8_t), offset);
- buffer[0] = header_.Checksum();
+ offset += Write(header_->Magic(), 8 * sizeof(uint8_t), offset);
+ buffer[0] = header_->Checksum();
offset += Write(buffer, sizeof(uint32_t), offset);
- offset += Write(header_.Signature(), 20 * sizeof(uint8_t), offset);
- uint32_t file_size = header_.FileSize();
+ offset += Write(header_->Signature(), 20 * sizeof(uint8_t), offset);
+ uint32_t file_size = header_->FileSize();
buffer[0] = file_size;
- buffer[1] = header_.GetSize();
- buffer[2] = header_.EndianTag();
- buffer[3] = header_.LinkSize();
- buffer[4] = header_.LinkOffset();
- buffer[5] = collections.MapItemOffset();
+ buffer[1] = header_->GetSize();
+ buffer[2] = header_->EndianTag();
+ buffer[3] = header_->LinkSize();
+ buffer[4] = header_->LinkOffset();
+ buffer[5] = collections.MapListOffset();
buffer[6] = collections.StringIdsSize();
buffer[7] = collections.StringIdsOffset();
buffer[8] = collections.TypeIdsSize();
@@ -617,12 +625,7 @@
Write(buffer, 20 * sizeof(uint32_t), offset);
}
-void DexWriter::WriteFile() {
- if (dex_file_.get() == nullptr) {
- fprintf(stderr, "Can't open output dex file\n");
- return;
- }
-
+void DexWriter::WriteMemMap() {
WriteStrings();
WriteTypes();
WriteTypeLists();
@@ -641,8 +644,9 @@
WriteHeader();
}
-void DexWriter::OutputDexFile(dex_ir::Header& header, const char* file_name) {
- (new DexWriter(header, file_name))->WriteFile();
+void DexWriter::Output(dex_ir::Header* header, MemMap* mem_map) {
+ DexWriter dex_writer(header, mem_map);
+ dex_writer.WriteMemMap();
}
} // namespace art
diff --git a/dexlayout/dex_writer.h b/dexlayout/dex_writer.h
index 9104295..fb76e5c 100644
--- a/dexlayout/dex_writer.h
+++ b/dexlayout/dex_writer.h
@@ -21,19 +21,19 @@
#include "base/unix_file/fd_file.h"
#include "dex_ir.h"
+#include "mem_map.h"
#include "os.h"
namespace art {
class DexWriter {
public:
- DexWriter(dex_ir::Header& header, const char* file_name) : header_(header),
- dex_file_(OS::CreateEmptyFileWriteOnly(file_name)) { }
+ DexWriter(dex_ir::Header* header, MemMap* mem_map) : header_(header), mem_map_(mem_map) { }
- static void OutputDexFile(dex_ir::Header& header, const char* file_name);
+ static void Output(dex_ir::Header* header, MemMap* mem_map);
private:
- void WriteFile();
+ void WriteMemMap();
size_t Write(const void* buffer, size_t length, size_t offset);
size_t WriteSleb128(uint32_t value, size_t offset);
@@ -62,13 +62,12 @@
void WriteMapItem();
void WriteHeader();
- dex_ir::Header& header_;
- std::unique_ptr<File> dex_file_;
+ dex_ir::Header* const header_;
+ MemMap* const mem_map_;
DISALLOW_COPY_AND_ASSIGN(DexWriter);
};
-
} // namespace art
#endif // ART_DEXLAYOUT_DEX_WRITER_H_
diff --git a/dexlayout/dexlayout.cc b/dexlayout/dexlayout.cc
index aa80655..cfe4837 100644
--- a/dexlayout/dexlayout.cc
+++ b/dexlayout/dexlayout.cc
@@ -37,27 +37,13 @@
#include "dex_visualize.h"
#include "dex_writer.h"
#include "jit/offline_profiling_info.h"
+#include "mem_map.h"
#include "os.h"
#include "utils.h"
namespace art {
/*
- * Options parsed in main driver.
- */
-struct Options options_;
-
-/*
- * Output file. Defaults to stdout.
- */
-FILE* out_file_ = stdout;
-
-/*
- * Profile information file.
- */
-ProfileCompilationInfo* profile_info_ = nullptr;
-
-/*
* Flags for use with createAccessFlagStr().
*/
enum AccessFor {
@@ -301,420 +287,65 @@
/*
* Dumps a string value with some escape characters.
*/
-static void DumpEscapedString(const char* p) {
- fputs("\"", out_file_);
+static void DumpEscapedString(const char* p, FILE* out_file) {
+ fputs("\"", out_file);
for (; *p; p++) {
switch (*p) {
case '\\':
- fputs("\\\\", out_file_);
+ fputs("\\\\", out_file);
break;
case '\"':
- fputs("\\\"", out_file_);
+ fputs("\\\"", out_file);
break;
case '\t':
- fputs("\\t", out_file_);
+ fputs("\\t", out_file);
break;
case '\n':
- fputs("\\n", out_file_);
+ fputs("\\n", out_file);
break;
case '\r':
- fputs("\\r", out_file_);
+ fputs("\\r", out_file);
break;
default:
- putc(*p, out_file_);
+ putc(*p, out_file);
} // switch
} // for
- fputs("\"", out_file_);
+ fputs("\"", out_file);
}
/*
* Dumps a string as an XML attribute value.
*/
-static void DumpXmlAttribute(const char* p) {
+static void DumpXmlAttribute(const char* p, FILE* out_file) {
for (; *p; p++) {
switch (*p) {
case '&':
- fputs("&", out_file_);
+ fputs("&", out_file);
break;
case '<':
- fputs("<", out_file_);
+ fputs("<", out_file);
break;
case '>':
- fputs(">", out_file_);
+ fputs(">", out_file);
break;
case '"':
- fputs(""", out_file_);
+ fputs(""", out_file);
break;
case '\t':
- fputs("	", out_file_);
+ fputs("	", out_file);
break;
case '\n':
- fputs("
", out_file_);
+ fputs("
", out_file);
break;
case '\r':
- fputs("
", out_file_);
+ fputs("
", out_file);
break;
default:
- putc(*p, out_file_);
+ putc(*p, out_file);
} // switch
} // for
}
-// Forward declare to resolve circular dependence.
-static void DumpEncodedValue(const dex_ir::EncodedValue* data);
-
-/*
- * Dumps encoded annotation.
- */
-static void DumpEncodedAnnotation(dex_ir::EncodedAnnotation* annotation) {
- fputs(annotation->GetType()->GetStringId()->Data(), out_file_);
- // Display all name=value pairs.
- for (auto& subannotation : *annotation->GetAnnotationElements()) {
- fputc(' ', out_file_);
- fputs(subannotation->GetName()->Data(), out_file_);
- fputc('=', out_file_);
- DumpEncodedValue(subannotation->GetValue());
- }
-}
-/*
- * Dumps encoded value.
- */
-static void DumpEncodedValue(const dex_ir::EncodedValue* data) {
- switch (data->Type()) {
- case DexFile::kDexAnnotationByte:
- fprintf(out_file_, "%" PRId8, data->GetByte());
- break;
- case DexFile::kDexAnnotationShort:
- fprintf(out_file_, "%" PRId16, data->GetShort());
- break;
- case DexFile::kDexAnnotationChar:
- fprintf(out_file_, "%" PRIu16, data->GetChar());
- break;
- case DexFile::kDexAnnotationInt:
- fprintf(out_file_, "%" PRId32, data->GetInt());
- break;
- case DexFile::kDexAnnotationLong:
- fprintf(out_file_, "%" PRId64, data->GetLong());
- break;
- case DexFile::kDexAnnotationFloat: {
- fprintf(out_file_, "%g", data->GetFloat());
- break;
- }
- case DexFile::kDexAnnotationDouble: {
- fprintf(out_file_, "%g", data->GetDouble());
- break;
- }
- case DexFile::kDexAnnotationString: {
- dex_ir::StringId* string_id = data->GetStringId();
- if (options_.output_format_ == kOutputPlain) {
- DumpEscapedString(string_id->Data());
- } else {
- DumpXmlAttribute(string_id->Data());
- }
- break;
- }
- case DexFile::kDexAnnotationType: {
- dex_ir::TypeId* type_id = data->GetTypeId();
- fputs(type_id->GetStringId()->Data(), out_file_);
- break;
- }
- case DexFile::kDexAnnotationField:
- case DexFile::kDexAnnotationEnum: {
- dex_ir::FieldId* field_id = data->GetFieldId();
- fputs(field_id->Name()->Data(), out_file_);
- break;
- }
- case DexFile::kDexAnnotationMethod: {
- dex_ir::MethodId* method_id = data->GetMethodId();
- fputs(method_id->Name()->Data(), out_file_);
- break;
- }
- case DexFile::kDexAnnotationArray: {
- fputc('{', out_file_);
- // Display all elements.
- for (auto& value : *data->GetEncodedArray()->GetEncodedValues()) {
- fputc(' ', out_file_);
- DumpEncodedValue(value.get());
- }
- fputs(" }", out_file_);
- break;
- }
- case DexFile::kDexAnnotationAnnotation: {
- DumpEncodedAnnotation(data->GetEncodedAnnotation());
- break;
- }
- case DexFile::kDexAnnotationNull:
- fputs("null", out_file_);
- break;
- case DexFile::kDexAnnotationBoolean:
- fputs(StrBool(data->GetBoolean()), out_file_);
- break;
- default:
- fputs("????", out_file_);
- break;
- } // switch
-}
-
-/*
- * Dumps the file header.
- */
-static void DumpFileHeader(dex_ir::Header* header) {
- char sanitized[8 * 2 + 1];
- dex_ir::Collections& collections = header->GetCollections();
- fprintf(out_file_, "DEX file header:\n");
- Asciify(sanitized, header->Magic(), 8);
- fprintf(out_file_, "magic : '%s'\n", sanitized);
- fprintf(out_file_, "checksum : %08x\n", header->Checksum());
- fprintf(out_file_, "signature : %02x%02x...%02x%02x\n",
- header->Signature()[0], header->Signature()[1],
- header->Signature()[DexFile::kSha1DigestSize - 2],
- header->Signature()[DexFile::kSha1DigestSize - 1]);
- fprintf(out_file_, "file_size : %d\n", header->FileSize());
- fprintf(out_file_, "header_size : %d\n", header->HeaderSize());
- fprintf(out_file_, "link_size : %d\n", header->LinkSize());
- fprintf(out_file_, "link_off : %d (0x%06x)\n",
- header->LinkOffset(), header->LinkOffset());
- fprintf(out_file_, "string_ids_size : %d\n", collections.StringIdsSize());
- fprintf(out_file_, "string_ids_off : %d (0x%06x)\n",
- collections.StringIdsOffset(), collections.StringIdsOffset());
- fprintf(out_file_, "type_ids_size : %d\n", collections.TypeIdsSize());
- fprintf(out_file_, "type_ids_off : %d (0x%06x)\n",
- collections.TypeIdsOffset(), collections.TypeIdsOffset());
- fprintf(out_file_, "proto_ids_size : %d\n", collections.ProtoIdsSize());
- fprintf(out_file_, "proto_ids_off : %d (0x%06x)\n",
- collections.ProtoIdsOffset(), collections.ProtoIdsOffset());
- fprintf(out_file_, "field_ids_size : %d\n", collections.FieldIdsSize());
- fprintf(out_file_, "field_ids_off : %d (0x%06x)\n",
- collections.FieldIdsOffset(), collections.FieldIdsOffset());
- fprintf(out_file_, "method_ids_size : %d\n", collections.MethodIdsSize());
- fprintf(out_file_, "method_ids_off : %d (0x%06x)\n",
- collections.MethodIdsOffset(), collections.MethodIdsOffset());
- fprintf(out_file_, "class_defs_size : %d\n", collections.ClassDefsSize());
- fprintf(out_file_, "class_defs_off : %d (0x%06x)\n",
- collections.ClassDefsOffset(), collections.ClassDefsOffset());
- fprintf(out_file_, "data_size : %d\n", header->DataSize());
- fprintf(out_file_, "data_off : %d (0x%06x)\n\n",
- header->DataOffset(), header->DataOffset());
-}
-
-/*
- * Dumps a class_def_item.
- */
-static void DumpClassDef(dex_ir::Header* header, int idx) {
- // General class information.
- dex_ir::ClassDef* class_def = header->GetCollections().GetClassDef(idx);
- fprintf(out_file_, "Class #%d header:\n", idx);
- fprintf(out_file_, "class_idx : %d\n", class_def->ClassType()->GetIndex());
- fprintf(out_file_, "access_flags : %d (0x%04x)\n",
- class_def->GetAccessFlags(), class_def->GetAccessFlags());
- uint32_t superclass_idx = class_def->Superclass() == nullptr ?
- DexFile::kDexNoIndex16 : class_def->Superclass()->GetIndex();
- fprintf(out_file_, "superclass_idx : %d\n", superclass_idx);
- fprintf(out_file_, "interfaces_off : %d (0x%06x)\n",
- class_def->InterfacesOffset(), class_def->InterfacesOffset());
- uint32_t source_file_offset = 0xffffffffU;
- if (class_def->SourceFile() != nullptr) {
- source_file_offset = class_def->SourceFile()->GetIndex();
- }
- fprintf(out_file_, "source_file_idx : %d\n", source_file_offset);
- uint32_t annotations_offset = 0;
- if (class_def->Annotations() != nullptr) {
- annotations_offset = class_def->Annotations()->GetOffset();
- }
- fprintf(out_file_, "annotations_off : %d (0x%06x)\n",
- annotations_offset, annotations_offset);
- if (class_def->GetClassData() == nullptr) {
- fprintf(out_file_, "class_data_off : %d (0x%06x)\n", 0, 0);
- } else {
- fprintf(out_file_, "class_data_off : %d (0x%06x)\n",
- class_def->GetClassData()->GetOffset(), class_def->GetClassData()->GetOffset());
- }
-
- // Fields and methods.
- dex_ir::ClassData* class_data = class_def->GetClassData();
- if (class_data != nullptr && class_data->StaticFields() != nullptr) {
- fprintf(out_file_, "static_fields_size : %zu\n", class_data->StaticFields()->size());
- } else {
- fprintf(out_file_, "static_fields_size : 0\n");
- }
- if (class_data != nullptr && class_data->InstanceFields() != nullptr) {
- fprintf(out_file_, "instance_fields_size: %zu\n", class_data->InstanceFields()->size());
- } else {
- fprintf(out_file_, "instance_fields_size: 0\n");
- }
- if (class_data != nullptr && class_data->DirectMethods() != nullptr) {
- fprintf(out_file_, "direct_methods_size : %zu\n", class_data->DirectMethods()->size());
- } else {
- fprintf(out_file_, "direct_methods_size : 0\n");
- }
- if (class_data != nullptr && class_data->VirtualMethods() != nullptr) {
- fprintf(out_file_, "virtual_methods_size: %zu\n", class_data->VirtualMethods()->size());
- } else {
- fprintf(out_file_, "virtual_methods_size: 0\n");
- }
- fprintf(out_file_, "\n");
-}
-
-/**
- * Dumps an annotation set item.
- */
-static void DumpAnnotationSetItem(dex_ir::AnnotationSetItem* set_item) {
- if (set_item == nullptr || set_item->GetItems()->size() == 0) {
- fputs(" empty-annotation-set\n", out_file_);
- return;
- }
- for (dex_ir::AnnotationItem* annotation : *set_item->GetItems()) {
- if (annotation == nullptr) {
- continue;
- }
- fputs(" ", out_file_);
- switch (annotation->GetVisibility()) {
- case DexFile::kDexVisibilityBuild: fputs("VISIBILITY_BUILD ", out_file_); break;
- case DexFile::kDexVisibilityRuntime: fputs("VISIBILITY_RUNTIME ", out_file_); break;
- case DexFile::kDexVisibilitySystem: fputs("VISIBILITY_SYSTEM ", out_file_); break;
- default: fputs("VISIBILITY_UNKNOWN ", out_file_); break;
- } // switch
- DumpEncodedAnnotation(annotation->GetAnnotation());
- fputc('\n', out_file_);
- }
-}
-
-/*
- * Dumps class annotations.
- */
-static void DumpClassAnnotations(dex_ir::Header* header, int idx) {
- dex_ir::ClassDef* class_def = header->GetCollections().GetClassDef(idx);
- dex_ir::AnnotationsDirectoryItem* annotations_directory = class_def->Annotations();
- if (annotations_directory == nullptr) {
- return; // none
- }
-
- fprintf(out_file_, "Class #%d annotations:\n", idx);
-
- dex_ir::AnnotationSetItem* class_set_item = annotations_directory->GetClassAnnotation();
- dex_ir::FieldAnnotationVector* fields = annotations_directory->GetFieldAnnotations();
- dex_ir::MethodAnnotationVector* methods = annotations_directory->GetMethodAnnotations();
- dex_ir::ParameterAnnotationVector* parameters = annotations_directory->GetParameterAnnotations();
-
- // Annotations on the class itself.
- if (class_set_item != nullptr) {
- fprintf(out_file_, "Annotations on class\n");
- DumpAnnotationSetItem(class_set_item);
- }
-
- // Annotations on fields.
- if (fields != nullptr) {
- for (auto& field : *fields) {
- const dex_ir::FieldId* field_id = field->GetFieldId();
- const uint32_t field_idx = field_id->GetIndex();
- const char* field_name = field_id->Name()->Data();
- fprintf(out_file_, "Annotations on field #%u '%s'\n", field_idx, field_name);
- DumpAnnotationSetItem(field->GetAnnotationSetItem());
- }
- }
-
- // Annotations on methods.
- if (methods != nullptr) {
- for (auto& method : *methods) {
- const dex_ir::MethodId* method_id = method->GetMethodId();
- const uint32_t method_idx = method_id->GetIndex();
- const char* method_name = method_id->Name()->Data();
- fprintf(out_file_, "Annotations on method #%u '%s'\n", method_idx, method_name);
- DumpAnnotationSetItem(method->GetAnnotationSetItem());
- }
- }
-
- // Annotations on method parameters.
- if (parameters != nullptr) {
- for (auto& parameter : *parameters) {
- const dex_ir::MethodId* method_id = parameter->GetMethodId();
- const uint32_t method_idx = method_id->GetIndex();
- const char* method_name = method_id->Name()->Data();
- fprintf(out_file_, "Annotations on method #%u '%s' parameters\n", method_idx, method_name);
- uint32_t j = 0;
- for (dex_ir::AnnotationSetItem* annotation : *parameter->GetAnnotations()->GetItems()) {
- fprintf(out_file_, "#%u\n", j);
- DumpAnnotationSetItem(annotation);
- ++j;
- }
- }
- }
-
- fputc('\n', out_file_);
-}
-
-/*
- * Dumps an interface that a class declares to implement.
- */
-static void DumpInterface(const dex_ir::TypeId* type_item, int i) {
- const char* interface_name = type_item->GetStringId()->Data();
- if (options_.output_format_ == kOutputPlain) {
- fprintf(out_file_, " #%d : '%s'\n", i, interface_name);
- } else {
- std::string dot(DescriptorToDotWrapper(interface_name));
- fprintf(out_file_, "<implements name=\"%s\">\n</implements>\n", dot.c_str());
- }
-}
-
-/*
- * Dumps the catches table associated with the code.
- */
-static void DumpCatches(const dex_ir::CodeItem* code) {
- const uint16_t tries_size = code->TriesSize();
-
- // No catch table.
- if (tries_size == 0) {
- fprintf(out_file_, " catches : (none)\n");
- return;
- }
-
- // Dump all table entries.
- fprintf(out_file_, " catches : %d\n", tries_size);
- std::vector<std::unique_ptr<const dex_ir::TryItem>>* tries = code->Tries();
- for (uint32_t i = 0; i < tries_size; i++) {
- const dex_ir::TryItem* try_item = (*tries)[i].get();
- const uint32_t start = try_item->StartAddr();
- const uint32_t end = start + try_item->InsnCount();
- fprintf(out_file_, " 0x%04x - 0x%04x\n", start, end);
- for (auto& handler : *try_item->GetHandlers()->GetHandlers()) {
- const dex_ir::TypeId* type_id = handler->GetTypeId();
- const char* descriptor = (type_id == nullptr) ? "<any>" : type_id->GetStringId()->Data();
- fprintf(out_file_, " %s -> 0x%04x\n", descriptor, handler->GetAddress());
- } // for
- } // for
-}
-
-/*
- * Dumps all positions table entries associated with the code.
- */
-static void DumpPositionInfo(const dex_ir::CodeItem* code) {
- dex_ir::DebugInfoItem* debug_info = code->DebugInfo();
- if (debug_info == nullptr) {
- return;
- }
- std::vector<std::unique_ptr<dex_ir::PositionInfo>>& positions = debug_info->GetPositionInfo();
- for (size_t i = 0; i < positions.size(); ++i) {
- fprintf(out_file_, " 0x%04x line=%d\n", positions[i]->address_, positions[i]->line_);
- }
-}
-
-/*
- * Dumps all locals table entries associated with the code.
- */
-static void DumpLocalInfo(const dex_ir::CodeItem* code) {
- dex_ir::DebugInfoItem* debug_info = code->DebugInfo();
- if (debug_info == nullptr) {
- return;
- }
- std::vector<std::unique_ptr<dex_ir::LocalInfo>>& locals = debug_info->GetLocalInfo();
- for (size_t i = 0; i < locals.size(); ++i) {
- dex_ir::LocalInfo* entry = locals[i].get();
- fprintf(out_file_, " 0x%04x - 0x%04x reg=%d %s %s %s\n",
- entry->start_address_, entry->end_address_, entry->reg_,
- entry->name_.c_str(), entry->descriptor_.c_str(), entry->signature_.c_str());
- }
-}
-
/*
* Helper for dumpInstruction(), which builds the string
* representation for the index in the given instruction.
@@ -723,11 +354,10 @@
static std::unique_ptr<char[]> IndexString(dex_ir::Header* header,
const Instruction* dec_insn,
size_t buf_size) {
- static const uint32_t kInvalidIndex = std::numeric_limits<uint32_t>::max();
std::unique_ptr<char[]> buf(new char[buf_size]);
// Determine index and width of the string.
uint32_t index = 0;
- uint32_t secondary_index = kInvalidIndex;
+ uint32_t secondary_index = DexFile::kDexNoIndex;
uint32_t width = 4;
switch (Instruction::FormatOf(dec_insn->Opcode())) {
// SOME NOT SUPPORTED:
@@ -756,7 +386,6 @@
index = dec_insn->VRegB();
secondary_index = dec_insn->VRegH();
width = 4;
- break;
default:
break;
} // switch
@@ -821,9 +450,6 @@
case Instruction::kIndexFieldOffset:
outSize = snprintf(buf.get(), buf_size, "[obj+%0*x]", width, index);
break;
- // SOME NOT SUPPORTED:
- // case Instruction::kIndexVaries:
- // case Instruction::kIndexInlineMethod:
case Instruction::kIndexMethodAndProtoRef: {
std::string method("<method?>");
std::string proto("<proto?>");
@@ -840,8 +466,11 @@
}
outSize = snprintf(buf.get(), buf_size, "%s, %s // method@%0*x, proto@%0*x",
method.c_str(), proto.c_str(), width, index, width, secondary_index);
- }
- break;
+ }
+ break;
+ // SOME NOT SUPPORTED:
+ // case Instruction::kIndexVaries:
+ // case Instruction::kIndexInlineMethod:
default:
outSize = snprintf(buf.get(), buf_size, "<?>");
break;
@@ -858,11 +487,365 @@
}
/*
+ * Dumps encoded annotation.
+ */
+void DexLayout::DumpEncodedAnnotation(dex_ir::EncodedAnnotation* annotation) {
+ fputs(annotation->GetType()->GetStringId()->Data(), out_file_);
+ // Display all name=value pairs.
+ for (auto& subannotation : *annotation->GetAnnotationElements()) {
+ fputc(' ', out_file_);
+ fputs(subannotation->GetName()->Data(), out_file_);
+ fputc('=', out_file_);
+ DumpEncodedValue(subannotation->GetValue());
+ }
+}
+/*
+ * Dumps encoded value.
+ */
+void DexLayout::DumpEncodedValue(const dex_ir::EncodedValue* data) {
+ switch (data->Type()) {
+ case DexFile::kDexAnnotationByte:
+ fprintf(out_file_, "%" PRId8, data->GetByte());
+ break;
+ case DexFile::kDexAnnotationShort:
+ fprintf(out_file_, "%" PRId16, data->GetShort());
+ break;
+ case DexFile::kDexAnnotationChar:
+ fprintf(out_file_, "%" PRIu16, data->GetChar());
+ break;
+ case DexFile::kDexAnnotationInt:
+ fprintf(out_file_, "%" PRId32, data->GetInt());
+ break;
+ case DexFile::kDexAnnotationLong:
+ fprintf(out_file_, "%" PRId64, data->GetLong());
+ break;
+ case DexFile::kDexAnnotationFloat: {
+ fprintf(out_file_, "%g", data->GetFloat());
+ break;
+ }
+ case DexFile::kDexAnnotationDouble: {
+ fprintf(out_file_, "%g", data->GetDouble());
+ break;
+ }
+ case DexFile::kDexAnnotationString: {
+ dex_ir::StringId* string_id = data->GetStringId();
+ if (options_.output_format_ == kOutputPlain) {
+ DumpEscapedString(string_id->Data(), out_file_);
+ } else {
+ DumpXmlAttribute(string_id->Data(), out_file_);
+ }
+ break;
+ }
+ case DexFile::kDexAnnotationType: {
+ dex_ir::TypeId* type_id = data->GetTypeId();
+ fputs(type_id->GetStringId()->Data(), out_file_);
+ break;
+ }
+ case DexFile::kDexAnnotationField:
+ case DexFile::kDexAnnotationEnum: {
+ dex_ir::FieldId* field_id = data->GetFieldId();
+ fputs(field_id->Name()->Data(), out_file_);
+ break;
+ }
+ case DexFile::kDexAnnotationMethod: {
+ dex_ir::MethodId* method_id = data->GetMethodId();
+ fputs(method_id->Name()->Data(), out_file_);
+ break;
+ }
+ case DexFile::kDexAnnotationArray: {
+ fputc('{', out_file_);
+ // Display all elements.
+ for (auto& value : *data->GetEncodedArray()->GetEncodedValues()) {
+ fputc(' ', out_file_);
+ DumpEncodedValue(value.get());
+ }
+ fputs(" }", out_file_);
+ break;
+ }
+ case DexFile::kDexAnnotationAnnotation: {
+ DumpEncodedAnnotation(data->GetEncodedAnnotation());
+ break;
+ }
+ case DexFile::kDexAnnotationNull:
+ fputs("null", out_file_);
+ break;
+ case DexFile::kDexAnnotationBoolean:
+ fputs(StrBool(data->GetBoolean()), out_file_);
+ break;
+ default:
+ fputs("????", out_file_);
+ break;
+ } // switch
+}
+
+/*
+ * Dumps the file header.
+ */
+void DexLayout::DumpFileHeader() {
+ char sanitized[8 * 2 + 1];
+ dex_ir::Collections& collections = header_->GetCollections();
+ fprintf(out_file_, "DEX file header:\n");
+ Asciify(sanitized, header_->Magic(), 8);
+ fprintf(out_file_, "magic : '%s'\n", sanitized);
+ fprintf(out_file_, "checksum : %08x\n", header_->Checksum());
+ fprintf(out_file_, "signature : %02x%02x...%02x%02x\n",
+ header_->Signature()[0], header_->Signature()[1],
+ header_->Signature()[DexFile::kSha1DigestSize - 2],
+ header_->Signature()[DexFile::kSha1DigestSize - 1]);
+ fprintf(out_file_, "file_size : %d\n", header_->FileSize());
+ fprintf(out_file_, "header_size : %d\n", header_->HeaderSize());
+ fprintf(out_file_, "link_size : %d\n", header_->LinkSize());
+ fprintf(out_file_, "link_off : %d (0x%06x)\n",
+ header_->LinkOffset(), header_->LinkOffset());
+ fprintf(out_file_, "string_ids_size : %d\n", collections.StringIdsSize());
+ fprintf(out_file_, "string_ids_off : %d (0x%06x)\n",
+ collections.StringIdsOffset(), collections.StringIdsOffset());
+ fprintf(out_file_, "type_ids_size : %d\n", collections.TypeIdsSize());
+ fprintf(out_file_, "type_ids_off : %d (0x%06x)\n",
+ collections.TypeIdsOffset(), collections.TypeIdsOffset());
+ fprintf(out_file_, "proto_ids_size : %d\n", collections.ProtoIdsSize());
+ fprintf(out_file_, "proto_ids_off : %d (0x%06x)\n",
+ collections.ProtoIdsOffset(), collections.ProtoIdsOffset());
+ fprintf(out_file_, "field_ids_size : %d\n", collections.FieldIdsSize());
+ fprintf(out_file_, "field_ids_off : %d (0x%06x)\n",
+ collections.FieldIdsOffset(), collections.FieldIdsOffset());
+ fprintf(out_file_, "method_ids_size : %d\n", collections.MethodIdsSize());
+ fprintf(out_file_, "method_ids_off : %d (0x%06x)\n",
+ collections.MethodIdsOffset(), collections.MethodIdsOffset());
+ fprintf(out_file_, "class_defs_size : %d\n", collections.ClassDefsSize());
+ fprintf(out_file_, "class_defs_off : %d (0x%06x)\n",
+ collections.ClassDefsOffset(), collections.ClassDefsOffset());
+ fprintf(out_file_, "data_size : %d\n", header_->DataSize());
+ fprintf(out_file_, "data_off : %d (0x%06x)\n\n",
+ header_->DataOffset(), header_->DataOffset());
+}
+
+/*
+ * Dumps a class_def_item.
+ */
+void DexLayout::DumpClassDef(int idx) {
+ // General class information.
+ dex_ir::ClassDef* class_def = header_->GetCollections().GetClassDef(idx);
+ fprintf(out_file_, "Class #%d header:\n", idx);
+ fprintf(out_file_, "class_idx : %d\n", class_def->ClassType()->GetIndex());
+ fprintf(out_file_, "access_flags : %d (0x%04x)\n",
+ class_def->GetAccessFlags(), class_def->GetAccessFlags());
+ uint32_t superclass_idx = class_def->Superclass() == nullptr ?
+ DexFile::kDexNoIndex16 : class_def->Superclass()->GetIndex();
+ fprintf(out_file_, "superclass_idx : %d\n", superclass_idx);
+ fprintf(out_file_, "interfaces_off : %d (0x%06x)\n",
+ class_def->InterfacesOffset(), class_def->InterfacesOffset());
+ uint32_t source_file_offset = 0xffffffffU;
+ if (class_def->SourceFile() != nullptr) {
+ source_file_offset = class_def->SourceFile()->GetIndex();
+ }
+ fprintf(out_file_, "source_file_idx : %d\n", source_file_offset);
+ uint32_t annotations_offset = 0;
+ if (class_def->Annotations() != nullptr) {
+ annotations_offset = class_def->Annotations()->GetOffset();
+ }
+ fprintf(out_file_, "annotations_off : %d (0x%06x)\n",
+ annotations_offset, annotations_offset);
+ if (class_def->GetClassData() == nullptr) {
+ fprintf(out_file_, "class_data_off : %d (0x%06x)\n", 0, 0);
+ } else {
+ fprintf(out_file_, "class_data_off : %d (0x%06x)\n",
+ class_def->GetClassData()->GetOffset(), class_def->GetClassData()->GetOffset());
+ }
+
+ // Fields and methods.
+ dex_ir::ClassData* class_data = class_def->GetClassData();
+ if (class_data != nullptr && class_data->StaticFields() != nullptr) {
+ fprintf(out_file_, "static_fields_size : %zu\n", class_data->StaticFields()->size());
+ } else {
+ fprintf(out_file_, "static_fields_size : 0\n");
+ }
+ if (class_data != nullptr && class_data->InstanceFields() != nullptr) {
+ fprintf(out_file_, "instance_fields_size: %zu\n", class_data->InstanceFields()->size());
+ } else {
+ fprintf(out_file_, "instance_fields_size: 0\n");
+ }
+ if (class_data != nullptr && class_data->DirectMethods() != nullptr) {
+ fprintf(out_file_, "direct_methods_size : %zu\n", class_data->DirectMethods()->size());
+ } else {
+ fprintf(out_file_, "direct_methods_size : 0\n");
+ }
+ if (class_data != nullptr && class_data->VirtualMethods() != nullptr) {
+ fprintf(out_file_, "virtual_methods_size: %zu\n", class_data->VirtualMethods()->size());
+ } else {
+ fprintf(out_file_, "virtual_methods_size: 0\n");
+ }
+ fprintf(out_file_, "\n");
+}
+
+/**
+ * Dumps an annotation set item.
+ */
+void DexLayout::DumpAnnotationSetItem(dex_ir::AnnotationSetItem* set_item) {
+ if (set_item == nullptr || set_item->GetItems()->size() == 0) {
+ fputs(" empty-annotation-set\n", out_file_);
+ return;
+ }
+ for (dex_ir::AnnotationItem* annotation : *set_item->GetItems()) {
+ if (annotation == nullptr) {
+ continue;
+ }
+ fputs(" ", out_file_);
+ switch (annotation->GetVisibility()) {
+ case DexFile::kDexVisibilityBuild: fputs("VISIBILITY_BUILD ", out_file_); break;
+ case DexFile::kDexVisibilityRuntime: fputs("VISIBILITY_RUNTIME ", out_file_); break;
+ case DexFile::kDexVisibilitySystem: fputs("VISIBILITY_SYSTEM ", out_file_); break;
+ default: fputs("VISIBILITY_UNKNOWN ", out_file_); break;
+ } // switch
+ DumpEncodedAnnotation(annotation->GetAnnotation());
+ fputc('\n', out_file_);
+ }
+}
+
+/*
+ * Dumps class annotations.
+ */
+void DexLayout::DumpClassAnnotations(int idx) {
+ dex_ir::ClassDef* class_def = header_->GetCollections().GetClassDef(idx);
+ dex_ir::AnnotationsDirectoryItem* annotations_directory = class_def->Annotations();
+ if (annotations_directory == nullptr) {
+ return; // none
+ }
+
+ fprintf(out_file_, "Class #%d annotations:\n", idx);
+
+ dex_ir::AnnotationSetItem* class_set_item = annotations_directory->GetClassAnnotation();
+ dex_ir::FieldAnnotationVector* fields = annotations_directory->GetFieldAnnotations();
+ dex_ir::MethodAnnotationVector* methods = annotations_directory->GetMethodAnnotations();
+ dex_ir::ParameterAnnotationVector* parameters = annotations_directory->GetParameterAnnotations();
+
+ // Annotations on the class itself.
+ if (class_set_item != nullptr) {
+ fprintf(out_file_, "Annotations on class\n");
+ DumpAnnotationSetItem(class_set_item);
+ }
+
+ // Annotations on fields.
+ if (fields != nullptr) {
+ for (auto& field : *fields) {
+ const dex_ir::FieldId* field_id = field->GetFieldId();
+ const uint32_t field_idx = field_id->GetIndex();
+ const char* field_name = field_id->Name()->Data();
+ fprintf(out_file_, "Annotations on field #%u '%s'\n", field_idx, field_name);
+ DumpAnnotationSetItem(field->GetAnnotationSetItem());
+ }
+ }
+
+ // Annotations on methods.
+ if (methods != nullptr) {
+ for (auto& method : *methods) {
+ const dex_ir::MethodId* method_id = method->GetMethodId();
+ const uint32_t method_idx = method_id->GetIndex();
+ const char* method_name = method_id->Name()->Data();
+ fprintf(out_file_, "Annotations on method #%u '%s'\n", method_idx, method_name);
+ DumpAnnotationSetItem(method->GetAnnotationSetItem());
+ }
+ }
+
+ // Annotations on method parameters.
+ if (parameters != nullptr) {
+ for (auto& parameter : *parameters) {
+ const dex_ir::MethodId* method_id = parameter->GetMethodId();
+ const uint32_t method_idx = method_id->GetIndex();
+ const char* method_name = method_id->Name()->Data();
+ fprintf(out_file_, "Annotations on method #%u '%s' parameters\n", method_idx, method_name);
+ uint32_t j = 0;
+ for (dex_ir::AnnotationSetItem* annotation : *parameter->GetAnnotations()->GetItems()) {
+ fprintf(out_file_, "#%u\n", j);
+ DumpAnnotationSetItem(annotation);
+ ++j;
+ }
+ }
+ }
+
+ fputc('\n', out_file_);
+}
+
+/*
+ * Dumps an interface that a class declares to implement.
+ */
+void DexLayout::DumpInterface(const dex_ir::TypeId* type_item, int i) {
+ const char* interface_name = type_item->GetStringId()->Data();
+ if (options_.output_format_ == kOutputPlain) {
+ fprintf(out_file_, " #%d : '%s'\n", i, interface_name);
+ } else {
+ std::string dot(DescriptorToDotWrapper(interface_name));
+ fprintf(out_file_, "<implements name=\"%s\">\n</implements>\n", dot.c_str());
+ }
+}
+
+/*
+ * Dumps the catches table associated with the code.
+ */
+void DexLayout::DumpCatches(const dex_ir::CodeItem* code) {
+ const uint16_t tries_size = code->TriesSize();
+
+ // No catch table.
+ if (tries_size == 0) {
+ fprintf(out_file_, " catches : (none)\n");
+ return;
+ }
+
+ // Dump all table entries.
+ fprintf(out_file_, " catches : %d\n", tries_size);
+ std::vector<std::unique_ptr<const dex_ir::TryItem>>* tries = code->Tries();
+ for (uint32_t i = 0; i < tries_size; i++) {
+ const dex_ir::TryItem* try_item = (*tries)[i].get();
+ const uint32_t start = try_item->StartAddr();
+ const uint32_t end = start + try_item->InsnCount();
+ fprintf(out_file_, " 0x%04x - 0x%04x\n", start, end);
+ for (auto& handler : *try_item->GetHandlers()->GetHandlers()) {
+ const dex_ir::TypeId* type_id = handler->GetTypeId();
+ const char* descriptor = (type_id == nullptr) ? "<any>" : type_id->GetStringId()->Data();
+ fprintf(out_file_, " %s -> 0x%04x\n", descriptor, handler->GetAddress());
+ } // for
+ } // for
+}
+
+/*
+ * Dumps all positions table entries associated with the code.
+ */
+void DexLayout::DumpPositionInfo(const dex_ir::CodeItem* code) {
+ dex_ir::DebugInfoItem* debug_info = code->DebugInfo();
+ if (debug_info == nullptr) {
+ return;
+ }
+ std::vector<std::unique_ptr<dex_ir::PositionInfo>>& positions = debug_info->GetPositionInfo();
+ for (size_t i = 0; i < positions.size(); ++i) {
+ fprintf(out_file_, " 0x%04x line=%d\n", positions[i]->address_, positions[i]->line_);
+ }
+}
+
+/*
+ * Dumps all locals table entries associated with the code.
+ */
+void DexLayout::DumpLocalInfo(const dex_ir::CodeItem* code) {
+ dex_ir::DebugInfoItem* debug_info = code->DebugInfo();
+ if (debug_info == nullptr) {
+ return;
+ }
+ std::vector<std::unique_ptr<dex_ir::LocalInfo>>& locals = debug_info->GetLocalInfo();
+ for (size_t i = 0; i < locals.size(); ++i) {
+ dex_ir::LocalInfo* entry = locals[i].get();
+ fprintf(out_file_, " 0x%04x - 0x%04x reg=%d %s %s %s\n",
+ entry->start_address_, entry->end_address_, entry->reg_,
+ entry->name_.c_str(), entry->descriptor_.c_str(), entry->signature_.c_str());
+ }
+}
+
+/*
* Dumps a single instruction.
*/
-static void DumpInstruction(dex_ir::Header* header, const dex_ir::CodeItem* code,
- uint32_t code_offset, uint32_t insn_idx, uint32_t insn_width,
- const Instruction* dec_insn) {
+void DexLayout::DumpInstruction(const dex_ir::CodeItem* code,
+ uint32_t code_offset,
+ uint32_t insn_idx,
+ uint32_t insn_width,
+ const Instruction* dec_insn) {
// Address of instruction (expressed as byte offset).
fprintf(out_file_, "%06x:", code_offset + 0x10 + insn_idx * 2);
@@ -901,7 +884,7 @@
// Set up additional argument.
std::unique_ptr<char[]> index_buf;
if (Instruction::IndexTypeOf(dec_insn->Opcode()) != Instruction::kIndexNone) {
- index_buf = IndexString(header, dec_insn, 200);
+ index_buf = IndexString(header_, dec_insn, 200);
}
// Dump the instruction.
@@ -1073,9 +1056,8 @@
/*
* Dumps a bytecode disassembly.
*/
-static void DumpBytecodes(dex_ir::Header* header, uint32_t idx,
- const dex_ir::CodeItem* code, uint32_t code_offset) {
- dex_ir::MethodId* method_id = header->GetCollections().GetMethodId(idx);
+void DexLayout::DumpBytecodes(uint32_t idx, const dex_ir::CodeItem* code, uint32_t code_offset) {
+ dex_ir::MethodId* method_id = header_->GetCollections().GetMethodId(idx);
const char* name = method_id->Name()->Data();
std::string type_descriptor = GetSignatureForProtoId(method_id->Proto());
const char* back_descriptor = method_id->Class()->GetStringId()->Data();
@@ -1094,7 +1076,7 @@
fprintf(stderr, "GLITCH: zero-width instruction at idx=0x%04x\n", insn_idx);
break;
}
- DumpInstruction(header, code, code_offset, insn_idx, insn_width, instruction);
+ DumpInstruction(code, code_offset, insn_idx, insn_width, instruction);
insn_idx += insn_width;
} // for
}
@@ -1102,8 +1084,7 @@
/*
* Dumps code of a method.
*/
-static void DumpCode(dex_ir::Header* header, uint32_t idx, const dex_ir::CodeItem* code,
- uint32_t code_offset) {
+void DexLayout::DumpCode(uint32_t idx, const dex_ir::CodeItem* code, uint32_t code_offset) {
fprintf(out_file_, " registers : %d\n", code->RegistersSize());
fprintf(out_file_, " ins : %d\n", code->InsSize());
fprintf(out_file_, " outs : %d\n", code->OutsSize());
@@ -1112,7 +1093,7 @@
// Bytecode disassembly, if requested.
if (options_.disassemble_) {
- DumpBytecodes(header, idx, code, code_offset);
+ DumpBytecodes(idx, code, code_offset);
}
// Try-catch blocks.
@@ -1128,14 +1109,13 @@
/*
* Dumps a method.
*/
-static void DumpMethod(dex_ir::Header* header, uint32_t idx, uint32_t flags,
- const dex_ir::CodeItem* code, int i) {
+void DexLayout::DumpMethod(uint32_t idx, uint32_t flags, const dex_ir::CodeItem* code, int i) {
// Bail for anything private if export only requested.
if (options_.exports_only_ && (flags & (kAccPublic | kAccProtected)) == 0) {
return;
}
- dex_ir::MethodId* method_id = header->GetCollections().GetMethodId(idx);
+ dex_ir::MethodId* method_id = header_->GetCollections().GetMethodId(idx);
const char* name = method_id->Name()->Data();
char* type_descriptor = strdup(GetSignatureForProtoId(method_id->Proto()).c_str());
const char* back_descriptor = method_id->Class()->GetStringId()->Data();
@@ -1150,7 +1130,7 @@
fprintf(out_file_, " code : (none)\n");
} else {
fprintf(out_file_, " code -\n");
- DumpCode(header, idx, code, code->GetOffset());
+ DumpCode(idx, code, code->GetOffset());
}
if (options_.disassemble_) {
fputc('\n', out_file_);
@@ -1233,14 +1213,13 @@
/*
* Dumps a static (class) field.
*/
-static void DumpSField(dex_ir::Header* header, uint32_t idx, uint32_t flags,
- int i, dex_ir::EncodedValue* init) {
+void DexLayout::DumpSField(uint32_t idx, uint32_t flags, int i, dex_ir::EncodedValue* init) {
// Bail for anything private if export only requested.
if (options_.exports_only_ && (flags & (kAccPublic | kAccProtected)) == 0) {
return;
}
- dex_ir::FieldId* field_id = header->GetCollections().GetFieldId(idx);
+ dex_ir::FieldId* field_id = header_->GetCollections().GetFieldId(idx);
const char* name = field_id->Name()->Data();
const char* type_descriptor = field_id->Type()->GetStringId()->Data();
const char* back_descriptor = field_id->Class()->GetStringId()->Data();
@@ -1281,8 +1260,8 @@
/*
* Dumps an instance field.
*/
-static void DumpIField(dex_ir::Header* header, uint32_t idx, uint32_t flags, int i) {
- DumpSField(header, idx, flags, i, nullptr);
+void DexLayout::DumpIField(uint32_t idx, uint32_t flags, int i) {
+ DumpSField(idx, flags, i, nullptr);
}
/*
@@ -1293,19 +1272,19 @@
* If "*last_package" is nullptr or does not match the current class' package,
* the value will be replaced with a newly-allocated string.
*/
-static void DumpClass(dex_ir::Header* header, int idx, char** last_package) {
- dex_ir::ClassDef* class_def = header->GetCollections().GetClassDef(idx);
+void DexLayout::DumpClass(int idx, char** last_package) {
+ dex_ir::ClassDef* class_def = header_->GetCollections().GetClassDef(idx);
// Omitting non-public class.
if (options_.exports_only_ && (class_def->GetAccessFlags() & kAccPublic) == 0) {
return;
}
if (options_.show_section_headers_) {
- DumpClassDef(header, idx);
+ DumpClassDef(idx);
}
if (options_.show_annotations_) {
- DumpClassAnnotations(header, idx);
+ DumpClassAnnotations(idx);
}
// For the XML output, show the package name. Ideally we'd gather
@@ -1313,7 +1292,7 @@
// package name wouldn't jump around, but that's not a great plan
// for something that needs to run on the device.
const char* class_descriptor =
- header->GetCollections().GetClassDef(idx)->ClassType()->GetStringId()->Data();
+ header_->GetCollections().GetClassDef(idx)->ClassType()->GetStringId()->Data();
if (!(class_descriptor[0] == 'L' &&
class_descriptor[strlen(class_descriptor)-1] == ';')) {
// Arrays and primitives should not be defined explicitly. Keep going?
@@ -1406,8 +1385,7 @@
dex_ir::FieldItemVector* static_fields = class_data->StaticFields();
if (static_fields != nullptr) {
for (uint32_t i = 0; i < static_fields->size(); i++) {
- DumpSField(header,
- (*static_fields)[i]->GetFieldId()->GetIndex(),
+ DumpSField((*static_fields)[i]->GetFieldId()->GetIndex(),
(*static_fields)[i]->GetAccessFlags(),
i,
i < encoded_values_size ? (*encoded_values)[i].get() : nullptr);
@@ -1423,8 +1401,7 @@
dex_ir::FieldItemVector* instance_fields = class_data->InstanceFields();
if (instance_fields != nullptr) {
for (uint32_t i = 0; i < instance_fields->size(); i++) {
- DumpIField(header,
- (*instance_fields)[i]->GetFieldId()->GetIndex(),
+ DumpIField((*instance_fields)[i]->GetFieldId()->GetIndex(),
(*instance_fields)[i]->GetAccessFlags(),
i);
} // for
@@ -1439,8 +1416,7 @@
dex_ir::MethodItemVector* direct_methods = class_data->DirectMethods();
if (direct_methods != nullptr) {
for (uint32_t i = 0; i < direct_methods->size(); i++) {
- DumpMethod(header,
- (*direct_methods)[i]->GetMethodId()->GetIndex(),
+ DumpMethod((*direct_methods)[i]->GetMethodId()->GetIndex(),
(*direct_methods)[i]->GetAccessFlags(),
(*direct_methods)[i]->GetCodeItem(),
i);
@@ -1456,8 +1432,7 @@
dex_ir::MethodItemVector* virtual_methods = class_data->VirtualMethods();
if (virtual_methods != nullptr) {
for (uint32_t i = 0; i < virtual_methods->size(); i++) {
- DumpMethod(header,
- (*virtual_methods)[i]->GetMethodId()->GetIndex(),
+ DumpMethod((*virtual_methods)[i]->GetMethodId()->GetIndex(),
(*virtual_methods)[i]->GetAccessFlags(),
(*virtual_methods)[i]->GetCodeItem(),
i);
@@ -1481,24 +1456,10 @@
free(access_str);
}
-/*
- * Dumps the requested sections of the file.
- */
-static void ProcessDexFile(const char* file_name, const DexFile* dex_file, size_t dex_file_index) {
- if (options_.verbose_) {
- fprintf(out_file_, "Opened '%s', DEX version '%.3s'\n",
- file_name, dex_file->GetHeader().magic_ + 4);
- }
- std::unique_ptr<dex_ir::Header> header(dex_ir::DexIrBuilder(*dex_file));
-
- if (options_.visualize_pattern_) {
- VisualizeDexLayout(header.get(), dex_file, dex_file_index);
- return;
- }
-
+void DexLayout::DumpDexFile() {
// Headers.
if (options_.show_file_headers_) {
- DumpFileHeader(header.get());
+ DumpFileHeader();
}
// Open XML context.
@@ -1508,9 +1469,9 @@
// Iterate over all classes.
char* package = nullptr;
- const uint32_t class_defs_size = header->GetCollections().ClassDefsSize();
+ const uint32_t class_defs_size = header_->GetCollections().ClassDefsSize();
for (uint32_t i = 0; i < class_defs_size; i++) {
- DumpClass(header.get(), i, &package);
+ DumpClass(i, &package);
} // for
// Free the last package allocated.
@@ -1523,20 +1484,227 @@
if (options_.output_format_ == kOutputXml) {
fprintf(out_file_, "</api>\n");
}
+}
- // Output dex file.
- if (options_.output_dex_directory_ != nullptr) {
+std::vector<dex_ir::ClassDef*> DexLayout::LayoutClassDefsAndClassData(const DexFile* dex_file) {
+ std::vector<dex_ir::ClassDef*> new_class_def_order;
+ for (std::unique_ptr<dex_ir::ClassDef>& class_def : header_->GetCollections().ClassDefs()) {
+ dex::TypeIndex type_idx(class_def->ClassType()->GetIndex());
+ if (info_->ContainsClass(*dex_file, type_idx)) {
+ new_class_def_order.push_back(class_def.get());
+ }
+ }
+ for (std::unique_ptr<dex_ir::ClassDef>& class_def : header_->GetCollections().ClassDefs()) {
+ dex::TypeIndex type_idx(class_def->ClassType()->GetIndex());
+ if (!info_->ContainsClass(*dex_file, type_idx)) {
+ new_class_def_order.push_back(class_def.get());
+ }
+ }
+ uint32_t class_defs_offset = header_->GetCollections().ClassDefsOffset();
+ uint32_t class_data_offset = header_->GetCollections().ClassDatasOffset();
+ for (uint32_t i = 0; i < new_class_def_order.size(); ++i) {
+ dex_ir::ClassDef* class_def = new_class_def_order[i];
+ class_def->SetIndex(i);
+ class_def->SetOffset(class_defs_offset);
+ class_defs_offset += dex_ir::ClassDef::ItemSize();
+ if (class_def->GetClassData() != nullptr) {
+ class_def->GetClassData()->SetOffset(class_data_offset);
+ class_data_offset += class_def->GetClassData()->GetSize();
+ }
+ }
+ return new_class_def_order;
+}
+
+int32_t DexLayout::LayoutCodeItems(std::vector<dex_ir::ClassDef*> new_class_def_order) {
+ int32_t diff = 0;
+ uint32_t offset = header_->GetCollections().CodeItemsOffset();
+ for (dex_ir::ClassDef* class_def : new_class_def_order) {
+ dex_ir::ClassData* class_data = class_def->GetClassData();
+ if (class_data != nullptr) {
+ class_data->SetOffset(class_data->GetOffset() + diff);
+ for (auto& method : *class_data->DirectMethods()) {
+ dex_ir::CodeItem* code_item = method->GetCodeItem();
+ if (code_item != nullptr) {
+ diff += UnsignedLeb128Size(offset) - UnsignedLeb128Size(code_item->GetOffset());
+ code_item->SetOffset(offset);
+ offset += RoundUp(code_item->GetSize(), 4);
+ }
+ }
+ for (auto& method : *class_data->VirtualMethods()) {
+ dex_ir::CodeItem* code_item = method->GetCodeItem();
+ if (code_item != nullptr) {
+ diff += UnsignedLeb128Size(offset) - UnsignedLeb128Size(code_item->GetOffset());
+ code_item->SetOffset(offset);
+ offset += RoundUp(code_item->GetSize(), 4);
+ }
+ }
+ }
+ }
+
+ return diff;
+}
+
+// Adjust offsets of every item in the specified section by diff bytes.
+template<class T> void DexLayout::FixupSection(std::map<uint32_t, std::unique_ptr<T>>& map,
+ uint32_t diff) {
+ for (auto& pair : map) {
+ std::unique_ptr<T>& item = pair.second;
+ item->SetOffset(item->GetOffset() + diff);
+ }
+}
+
+// Adjust offsets of all sections with an address after the specified offset by diff bytes.
+void DexLayout::FixupSections(uint32_t offset, uint32_t diff) {
+ dex_ir::Collections& collections = header_->GetCollections();
+ uint32_t map_list_offset = collections.MapListOffset();
+ if (map_list_offset > offset) {
+ collections.SetMapListOffset(map_list_offset + diff);
+ }
+
+ uint32_t type_lists_offset = collections.TypeListsOffset();
+ if (type_lists_offset > offset) {
+ collections.SetTypeListsOffset(type_lists_offset + diff);
+ FixupSection(collections.TypeLists(), diff);
+ }
+
+ uint32_t annotation_set_ref_lists_offset = collections.AnnotationSetRefListsOffset();
+ if (annotation_set_ref_lists_offset > offset) {
+ collections.SetAnnotationSetRefListsOffset(annotation_set_ref_lists_offset + diff);
+ FixupSection(collections.AnnotationSetRefLists(), diff);
+ }
+
+ uint32_t annotation_set_items_offset = collections.AnnotationSetItemsOffset();
+ if (annotation_set_items_offset > offset) {
+ collections.SetAnnotationSetItemsOffset(annotation_set_items_offset + diff);
+ FixupSection(collections.AnnotationSetItems(), diff);
+ }
+
+ uint32_t class_datas_offset = collections.ClassDatasOffset();
+ if (class_datas_offset > offset) {
+ collections.SetClassDatasOffset(class_datas_offset + diff);
+ FixupSection(collections.ClassDatas(), diff);
+ }
+
+ uint32_t code_items_offset = collections.CodeItemsOffset();
+ if (code_items_offset > offset) {
+ collections.SetCodeItemsOffset(code_items_offset + diff);
+ FixupSection(collections.CodeItems(), diff);
+ }
+
+ uint32_t string_datas_offset = collections.StringDatasOffset();
+ if (string_datas_offset > offset) {
+ collections.SetStringDatasOffset(string_datas_offset + diff);
+ FixupSection(collections.StringDatas(), diff);
+ }
+
+ uint32_t debug_info_items_offset = collections.DebugInfoItemsOffset();
+ if (debug_info_items_offset > offset) {
+ collections.SetDebugInfoItemsOffset(debug_info_items_offset + diff);
+ FixupSection(collections.DebugInfoItems(), diff);
+ }
+
+ uint32_t annotation_items_offset = collections.AnnotationItemsOffset();
+ if (annotation_items_offset > offset) {
+ collections.SetAnnotationItemsOffset(annotation_items_offset + diff);
+ FixupSection(collections.AnnotationItems(), diff);
+ }
+
+ uint32_t encoded_array_items_offset = collections.EncodedArrayItemsOffset();
+ if (encoded_array_items_offset > offset) {
+ collections.SetEncodedArrayItemsOffset(encoded_array_items_offset + diff);
+ FixupSection(collections.EncodedArrayItems(), diff);
+ }
+
+ uint32_t annotations_directory_items_offset = collections.AnnotationsDirectoryItemsOffset();
+ if (annotations_directory_items_offset > offset) {
+ collections.SetAnnotationsDirectoryItemsOffset(annotations_directory_items_offset + diff);
+ FixupSection(collections.AnnotationsDirectoryItems(), diff);
+ }
+}
+
+void DexLayout::LayoutOutputFile(const DexFile* dex_file) {
+ std::vector<dex_ir::ClassDef*> new_class_def_order = LayoutClassDefsAndClassData(dex_file);
+ int32_t diff = LayoutCodeItems(new_class_def_order);
+ // Adjust diff to be 4-byte aligned.
+ diff = RoundUp(diff, 4);
+ // Move sections after ClassData by diff bytes.
+ FixupSections(header_->GetCollections().ClassDatasOffset(), diff);
+ // Update file size.
+ header_->SetFileSize(header_->FileSize() + diff);
+}
+
+void DexLayout::OutputDexFile(const std::string& dex_file_location) {
+ std::string error_msg;
+ std::unique_ptr<File> new_file;
+ if (!options_.output_to_memmap_) {
std::string output_location(options_.output_dex_directory_);
- size_t last_slash = dex_file->GetLocation().rfind('/');
- output_location.append(dex_file->GetLocation().substr(last_slash));
- DexWriter::OutputDexFile(*header, output_location.c_str());
+ size_t last_slash = dex_file_location.rfind("/");
+ std::string dex_file_directory = dex_file_location.substr(0, last_slash + 1);
+ if (output_location == dex_file_directory) {
+ output_location = dex_file_location + ".new";
+ } else if (last_slash != std::string::npos) {
+ output_location += dex_file_location.substr(last_slash);
+ } else {
+ output_location += "/" + dex_file_location + ".new";
+ }
+ new_file.reset(OS::CreateEmptyFile(output_location.c_str()));
+ ftruncate(new_file->Fd(), header_->FileSize());
+ mem_map_.reset(MemMap::MapFile(header_->FileSize(), PROT_READ | PROT_WRITE, MAP_SHARED,
+ new_file->Fd(), 0, /*low_4gb*/ false, output_location.c_str(), &error_msg));
+ } else {
+ mem_map_.reset(MemMap::MapAnonymous("layout dex", nullptr, header_->FileSize(),
+ PROT_READ | PROT_WRITE, /* low_4gb */ false, /* reuse */ false, &error_msg));
+ }
+ if (mem_map_ == nullptr) {
+ LOG(ERROR) << "Could not create mem map for dex writer output: " << error_msg;
+ if (new_file.get() != nullptr) {
+ new_file->Erase();
+ }
+ return;
+ }
+ DexWriter::Output(header_, mem_map_.get());
+ if (new_file != nullptr) {
+ UNUSED(new_file->FlushCloseOrErase());
+ }
+}
+
+/*
+ * Dumps the requested sections of the file.
+ */
+void DexLayout::ProcessDexFile(const char* file_name,
+ const DexFile* dex_file,
+ size_t dex_file_index) {
+ std::unique_ptr<dex_ir::Header> header(dex_ir::DexIrBuilder(*dex_file));
+ SetHeader(header.get());
+
+ if (options_.verbose_) {
+ fprintf(out_file_, "Opened '%s', DEX version '%.3s'\n",
+ file_name, dex_file->GetHeader().magic_ + 4);
+ }
+
+ if (options_.visualize_pattern_) {
+ VisualizeDexLayout(header_, dex_file, dex_file_index, info_);
+ return;
+ }
+
+ // Dump dex file.
+ if (options_.dump_) {
+ DumpDexFile();
+ }
+
+ // Output dex file as file or memmap.
+ if (options_.output_dex_directory_ != nullptr || options_.output_to_memmap_) {
+ if (info_ != nullptr) {
+ LayoutOutputFile(dex_file);
+ }
+ OutputDexFile(dex_file->GetLocation());
}
}
/*
* Processes a single file (either direct .dex or indirect .zip/.jar/.apk).
*/
-int ProcessFile(const char* file_name) {
+int DexLayout::ProcessFile(const char* file_name) {
if (options_.verbose_) {
fprintf(out_file_, "Processing '%s'...\n", file_name);
}
diff --git a/dexlayout/dexlayout.h b/dexlayout/dexlayout.h
index a5bd992..ac1a4a6 100644
--- a/dexlayout/dexlayout.h
+++ b/dexlayout/dexlayout.h
@@ -26,8 +26,13 @@
#include <stdint.h>
#include <stdio.h>
+#include "dex_ir.h"
+#include "mem_map.h"
+
namespace art {
+class DexFile;
+class Instruction;
class ProfileCompilationInfo;
/* Supported output formats. */
@@ -37,28 +42,90 @@
};
/* Command-line options. */
-struct Options {
- bool build_dex_ir_;
- bool checksum_only_;
- bool disassemble_;
- bool exports_only_;
- bool ignore_bad_checksum_;
- bool show_annotations_;
- bool show_file_headers_;
- bool show_section_headers_;
- bool verbose_;
- bool visualize_pattern_;
- OutputFormat output_format_;
- const char* output_dex_directory_;
- const char* output_file_name_;
- const char* profile_file_name_;
+class Options {
+ public:
+ Options() = default;
+
+ bool dump_ = false;
+ bool build_dex_ir_ = false;
+ bool checksum_only_ = false;
+ bool disassemble_ = false;
+ bool exports_only_ = false;
+ bool ignore_bad_checksum_ = false;
+ bool output_to_memmap_ = false;
+ bool show_annotations_ = false;
+ bool show_file_headers_ = false;
+ bool show_section_headers_ = false;
+ bool verbose_ = false;
+ bool visualize_pattern_ = false;
+ OutputFormat output_format_ = kOutputPlain;
+ const char* output_dex_directory_ = nullptr;
+ const char* output_file_name_ = nullptr;
+ const char* profile_file_name_ = nullptr;
};
-/* Prototypes. */
-extern struct Options options_;
-extern FILE* out_file_;
-extern ProfileCompilationInfo* profile_info_;
-int ProcessFile(const char* file_name);
+class DexLayout {
+ public:
+ DexLayout(Options& options,
+ ProfileCompilationInfo* info,
+ FILE* out_file,
+ dex_ir::Header*
+ header = nullptr)
+ : options_(options), info_(info), out_file_(out_file), header_(header) { }
+
+ int ProcessFile(const char* file_name);
+ void ProcessDexFile(const char* file_name, const DexFile* dex_file, size_t dex_file_index);
+
+ dex_ir::Header* GetHeader() const { return header_; }
+ void SetHeader(dex_ir::Header* header) { header_ = header; }
+
+ MemMap* GetAndReleaseMemMap() { return mem_map_.release(); }
+
+ private:
+ void DumpAnnotationSetItem(dex_ir::AnnotationSetItem* set_item);
+ void DumpBytecodes(uint32_t idx, const dex_ir::CodeItem* code, uint32_t code_offset);
+ void DumpCatches(const dex_ir::CodeItem* code);
+ void DumpClass(int idx, char** last_package);
+ void DumpClassAnnotations(int idx);
+ void DumpClassDef(int idx);
+ void DumpCode(uint32_t idx, const dex_ir::CodeItem* code, uint32_t code_offset);
+ void DumpEncodedAnnotation(dex_ir::EncodedAnnotation* annotation);
+ void DumpEncodedValue(const dex_ir::EncodedValue* data);
+ void DumpFileHeader();
+ void DumpIField(uint32_t idx, uint32_t flags, int i);
+ void DumpInstruction(const dex_ir::CodeItem* code,
+ uint32_t code_offset,
+ uint32_t insn_idx,
+ uint32_t insn_width,
+ const Instruction* dec_insn);
+ void DumpInterface(const dex_ir::TypeId* type_item, int i);
+ void DumpLocalInfo(const dex_ir::CodeItem* code);
+ void DumpMethod(uint32_t idx, uint32_t flags, const dex_ir::CodeItem* code, int i);
+ void DumpPositionInfo(const dex_ir::CodeItem* code);
+ void DumpSField(uint32_t idx, uint32_t flags, int i, dex_ir::EncodedValue* init);
+ void DumpDexFile();
+
+ std::vector<dex_ir::ClassDef*> LayoutClassDefsAndClassData(const DexFile* dex_file);
+ int32_t LayoutCodeItems(std::vector<dex_ir::ClassDef*> new_class_def_order);
+ template<class T> void FixupSection(std::map<uint32_t, std::unique_ptr<T>>& map, uint32_t diff);
+ void FixupSections(uint32_t offset, uint32_t diff);
+
+ // Creates a new layout for the dex file based on profile info.
+ // Currently reorders ClassDefs, ClassDataItems, and CodeItems.
+ void LayoutOutputFile(const DexFile* dex_file);
+ void OutputDexFile(const std::string& dex_file_location);
+
+ void DumpCFG(const DexFile* dex_file, int idx);
+ void DumpCFG(const DexFile* dex_file, uint32_t dex_method_idx, const DexFile::CodeItem* code);
+
+ Options& options_;
+ ProfileCompilationInfo* info_;
+ FILE* out_file_;
+ dex_ir::Header* header_;
+ std::unique_ptr<MemMap> mem_map_;
+
+ DISALLOW_COPY_AND_ASSIGN(DexLayout);
+};
} // namespace art
diff --git a/dexlayout/dexlayout_main.cc b/dexlayout/dexlayout_main.cc
index 825dd50..5f8a118 100644
--- a/dexlayout/dexlayout_main.cc
+++ b/dexlayout/dexlayout_main.cc
@@ -68,64 +68,67 @@
InitLogging(argv, Runtime::Aborter);
MemMap::Init();
- // Reset options.
+ Options options;
+ options.dump_ = true;
+ options.verbose_ = true;
bool want_usage = false;
- memset(&options_, 0, sizeof(options_));
- options_.verbose_ = true;
// Parse all arguments.
while (1) {
- const int ic = getopt(argc, argv, "abcdefghil:o:p:sw:");
+ const int ic = getopt(argc, argv, "abcdefghil:mo:p:sw:");
if (ic < 0) {
break; // done
}
switch (ic) {
case 'a': // display annotations
- options_.show_annotations_ = true;
+ options.show_annotations_ = true;
break;
case 'b': // build dex_ir
- options_.build_dex_ir_ = true;
+ options.build_dex_ir_ = true;
break;
case 'c': // verify the checksum then exit
- options_.checksum_only_ = true;
+ options.checksum_only_ = true;
break;
case 'd': // disassemble Dalvik instructions
- options_.disassemble_ = true;
+ options.disassemble_ = true;
break;
case 'e': // exported items only
- options_.exports_only_ = true;
+ options.exports_only_ = true;
break;
case 'f': // display outer file header
- options_.show_file_headers_ = true;
+ options.show_file_headers_ = true;
break;
case 'h': // display section headers, i.e. all meta-data
- options_.show_section_headers_ = true;
+ options.show_section_headers_ = true;
break;
case 'i': // continue even if checksum is bad
- options_.ignore_bad_checksum_ = true;
+ options.ignore_bad_checksum_ = true;
break;
case 'l': // layout
if (strcmp(optarg, "plain") == 0) {
- options_.output_format_ = kOutputPlain;
+ options.output_format_ = kOutputPlain;
} else if (strcmp(optarg, "xml") == 0) {
- options_.output_format_ = kOutputXml;
- options_.verbose_ = false;
+ options.output_format_ = kOutputXml;
+ options.verbose_ = false;
} else {
want_usage = true;
}
break;
+ case 'm': // output dex files to a memmap
+ options.output_to_memmap_ = true;
+ break;
case 'o': // output file
- options_.output_file_name_ = optarg;
+ options.output_file_name_ = optarg;
break;
case 'p': // profile file
- options_.profile_file_name_ = optarg;
+ options.profile_file_name_ = optarg;
break;
case 's': // visualize access pattern
- options_.visualize_pattern_ = true;
- options_.verbose_ = false;
+ options.visualize_pattern_ = true;
+ options.verbose_ = false;
break;
case 'w': // output dex files directory
- options_.output_dex_directory_ = optarg;
+ options.output_dex_directory_ = optarg;
break;
default:
want_usage = true;
@@ -138,7 +141,7 @@
fprintf(stderr, "%s: no file specified\n", kProgramName);
want_usage = true;
}
- if (options_.checksum_only_ && options_.ignore_bad_checksum_) {
+ if (options.checksum_only_ && options.ignore_bad_checksum_) {
fprintf(stderr, "Can't specify both -c and -i\n");
want_usage = true;
}
@@ -148,32 +151,37 @@
}
// Open alternative output file.
- if (options_.output_file_name_) {
- out_file_ = fopen(options_.output_file_name_, "w");
- if (!out_file_) {
- fprintf(stderr, "Can't open %s\n", options_.output_file_name_);
+ FILE* out_file = stdout;
+ if (options.output_file_name_) {
+ out_file = fopen(options.output_file_name_, "w");
+ if (!out_file) {
+ fprintf(stderr, "Can't open %s\n", options.output_file_name_);
return 1;
}
}
// Open profile file.
- if (options_.profile_file_name_) {
- int profile_fd = open(options_.profile_file_name_, O_RDONLY);
+ ProfileCompilationInfo* profile_info = nullptr;
+ if (options.profile_file_name_) {
+ int profile_fd = open(options.profile_file_name_, O_RDONLY);
if (profile_fd < 0) {
- fprintf(stderr, "Can't open %s\n", options_.profile_file_name_);
+ fprintf(stderr, "Can't open %s\n", options.profile_file_name_);
return 1;
}
- profile_info_ = new ProfileCompilationInfo();
- if (!profile_info_->Load(profile_fd)) {
- fprintf(stderr, "Can't read profile info from %s\n", options_.profile_file_name_);
+ profile_info = new ProfileCompilationInfo();
+ if (!profile_info->Load(profile_fd)) {
+ fprintf(stderr, "Can't read profile info from %s\n", options.profile_file_name_);
return 1;
}
}
+ // Create DexLayout instance.
+ DexLayout dex_layout(options, profile_info, out_file);
+
// Process all files supplied on command line.
int result = 0;
while (optind < argc) {
- result |= ProcessFile(argv[optind++]);
+ result |= dex_layout.ProcessFile(argv[optind++]);
} // while
return result != 0;
}
diff --git a/dexlayout/dexlayout_test.cc b/dexlayout/dexlayout_test.cc
index c7f36be..665baa6 100644
--- a/dexlayout/dexlayout_test.cc
+++ b/dexlayout/dexlayout_test.cc
@@ -22,11 +22,57 @@
#include <unistd.h>
#include "base/stringprintf.h"
+#include "base/unix_file/fd_file.h"
#include "common_runtime_test.h"
#include "utils.h"
namespace art {
+static const char kDexFileLayoutInputDex[] =
+ "ZGV4CjAzNQD1KW3+B8NAB0f2A/ZVIBJ0aHrGIqcpVTAUAgAAcAAAAHhWNBIAAAAAAAAAAIwBAAAH"
+ "AAAAcAAAAAQAAACMAAAAAQAAAJwAAAAAAAAAAAAAAAMAAACoAAAAAgAAAMAAAAAUAQAAAAEAADAB"
+ "AAA4AQAAQAEAAEgBAABNAQAAUgEAAGYBAAADAAAABAAAAAUAAAAGAAAABgAAAAMAAAAAAAAAAAAA"
+ "AAAAAAABAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAEAAAAAAAAAdQEAAAAAAAABAAAA"
+ "AAAAAAIAAAAAAAAAAgAAAAAAAAB/AQAAAAAAAAEAAQABAAAAaQEAAAQAAABwEAIAAAAOAAEAAQAB"
+ "AAAAbwEAAAQAAABwEAIAAAAOAAY8aW5pdD4ABkEuamF2YQAGQi5qYXZhAANMQTsAA0xCOwASTGph"
+ "dmEvbGFuZy9PYmplY3Q7AAFWAAQABw48AAQABw48AAAAAQAAgIAEgAIAAAEAAYCABJgCAAAACwAA"
+ "AAAAAAABAAAAAAAAAAEAAAAHAAAAcAAAAAIAAAAEAAAAjAAAAAMAAAABAAAAnAAAAAUAAAADAAAA"
+ "qAAAAAYAAAACAAAAwAAAAAEgAAACAAAAAAEAAAIgAAAHAAAAMAEAAAMgAAACAAAAaQEAAAAgAAAC"
+ "AAAAdQEAAAAQAAABAAAAjAEAAA==";
+
+static const char kDexFileLayoutInputProfile[] =
+ "cHJvADAwMgABAAsAAAABAPUpbf5jbGFzc2VzLmRleAEA";
+
+static const char kDexFileLayoutExpectedOutputDex[] =
+ "ZGV4CjAzNQD1KW3+B8NAB0f2A/ZVIBJ0aHrGIqcpVTAUAgAAcAAAAHhWNBIAAAAAAAAAAIwBAAAH"
+ "AAAAcAAAAAQAAACMAAAAAQAAAJwAAAAAAAAAAAAAAAMAAACoAAAAAgAAAMAAAAAUAQAAAAEAADAB"
+ "AAA4AQAAQAEAAEgBAABNAQAAUgEAAGYBAAADAAAABAAAAAUAAAAGAAAABgAAAAMAAAAAAAAAAAAA"
+ "AAAAAAABAAAAAAAAAAIAAAAAAAAAAQAAAAAAAAACAAAAAAAAAAIAAAAAAAAAdQEAAAAAAAAAAAAA"
+ "AAAAAAIAAAAAAAAAAQAAAAAAAAB/AQAAAAAAAAEAAQABAAAAbwEAAAQAAABwEAIAAAAOAAEAAQAB"
+ "AAAAaQEAAAQAAABwEAIAAAAOAAY8aW5pdD4ABkEuamF2YQAGQi5qYXZhAANMQTsAA0xCOwASTGph"
+ "dmEvbGFuZy9PYmplY3Q7AAFWAAQABw48AAQABw48AAAAAQABgIAEgAIAAAEAAICABJgCAAAACwAA"
+ "AAAAAAABAAAAAAAAAAEAAAAHAAAAcAAAAAIAAAAEAAAAjAAAAAMAAAABAAAAnAAAAAUAAAADAAAA"
+ "qAAAAAYAAAACAAAAwAAAAAEgAAACAAAAAAEAAAIgAAAHAAAAMAEAAAMgAAACAAAAaQEAAAAgAAAC"
+ "AAAAdQEAAAAQAAABAAAAjAEAAA==";
+
+static void WriteFileBase64(const char* base64, const char* location) {
+ // Decode base64.
+ CHECK(base64 != nullptr);
+ size_t length;
+ std::unique_ptr<uint8_t[]> bytes(DecodeBase64(base64, &length));
+ CHECK(bytes.get() != nullptr);
+
+ // Write to provided file.
+ std::unique_ptr<File> file(OS::CreateEmptyFile(location));
+ CHECK(file.get() != nullptr);
+ if (!file->WriteFully(bytes.get(), length)) {
+ PLOG(FATAL) << "Failed to write base64 as file";
+ }
+ if (file->FlushCloseOrErase() != 0) {
+ PLOG(FATAL) << "Could not flush and close test file.";
+ }
+}
+
class DexLayoutTest : public CommonRuntimeTest {
protected:
virtual void SetUp() {
@@ -51,7 +97,6 @@
{ dexdump, "-d", "-f", "-h", "-l", "plain", "-o", dexdump_filename, dex_file };
std::vector<std::string> dexlayout_exec_argv =
{ dexlayout, "-d", "-f", "-h", "-l", "plain", "-o", dexlayout_filename, dex_file };
-
if (!::art::Exec(dexdump_exec_argv, error_msg)) {
return false;
}
@@ -78,13 +123,11 @@
for (const std::string &dex_file : GetLibCoreDexFileNames()) {
std::vector<std::string> dexlayout_exec_argv =
- { dexlayout, "-d", "-f", "-h", "-l", "plain", "-w", tmp_dir, "-o", tmp_name, dex_file };
-
+ { dexlayout, "-w", tmp_dir, "-o", tmp_name, dex_file };
if (!::art::Exec(dexlayout_exec_argv, error_msg)) {
return false;
}
-
- size_t dex_file_last_slash = dex_file.rfind('/');
+ size_t dex_file_last_slash = dex_file.rfind("/");
std::string dex_file_name = dex_file.substr(dex_file_last_slash + 1);
std::vector<std::string> unzip_exec_argv =
{ "/usr/bin/unzip", dex_file, "classes.dex", "-d", tmp_dir};
@@ -105,7 +148,44 @@
return false;
}
}
+ return true;
+ }
+ // Runs DexFileOutput test.
+ bool DexFileLayoutExec(std::string* error_msg) {
+ ScratchFile tmp_file;
+ std::string tmp_name = tmp_file.GetFilename();
+ size_t tmp_last_slash = tmp_name.rfind("/");
+ std::string tmp_dir = tmp_name.substr(0, tmp_last_slash + 1);
+
+ // Write inputs and expected outputs.
+ std::string dex_file = tmp_dir + "classes.dex";
+ WriteFileBase64(kDexFileLayoutInputDex, dex_file.c_str());
+ std::string profile_file = tmp_dir + "primary.prof";
+ WriteFileBase64(kDexFileLayoutInputProfile, profile_file.c_str());
+ std::string expected_output = tmp_dir + "expected.dex";
+ WriteFileBase64(kDexFileLayoutExpectedOutputDex, expected_output.c_str());
+ std::string output_dex = tmp_dir + "classes.dex.new";
+
+ std::string dexlayout = GetTestAndroidRoot() + "/bin/dexlayout";
+ EXPECT_TRUE(OS::FileExists(dexlayout.c_str())) << dexlayout << " should be a valid file path";
+
+ std::vector<std::string> dexlayout_exec_argv =
+ { dexlayout, "-w", tmp_dir, "-o", tmp_name, "-p", profile_file, dex_file };
+ if (!::art::Exec(dexlayout_exec_argv, error_msg)) {
+ return false;
+ }
+ std::vector<std::string> diff_exec_argv =
+ { "/usr/bin/diff", expected_output, output_dex };
+ if (!::art::Exec(diff_exec_argv, error_msg)) {
+ return false;
+ }
+
+ std::vector<std::string> rm_exec_argv =
+ { "/bin/rm", dex_file, profile_file, expected_output, output_dex };
+ if (!::art::Exec(rm_exec_argv, error_msg)) {
+ return false;
+ }
return true;
}
};
@@ -125,4 +205,11 @@
ASSERT_TRUE(DexFileOutputExec(&error_msg)) << error_msg;
}
+TEST_F(DexLayoutTest, DexFileLayout) {
+ // Disable test on target.
+ TEST_DISABLED_FOR_TARGET();
+ std::string error_msg;
+ ASSERT_TRUE(DexFileLayoutExec(&error_msg)) << error_msg;
+}
+
} // namespace art
diff --git a/disassembler/disassembler_arm.cc b/disassembler/disassembler_arm.cc
index 30b708c..3347dac 100644
--- a/disassembler/disassembler_arm.cc
+++ b/disassembler/disassembler_arm.cc
@@ -63,9 +63,7 @@
case kVld2Location:
case kVld3Location:
case kVld4Location: {
- const uintptr_t pc_delta = disasm_->IsT32()
- ? vixl::aarch32::kT32PcDelta
- : vixl::aarch32::kA32PcDelta;
+ const uintptr_t pc_delta = label.GetLabel()->GetPcOffset();
const int32_t offset = label.GetLabel()->GetLocation();
os() << "[pc, #" << offset - pc_delta << "]";
@@ -77,7 +75,7 @@
}
}
- DisassemblerStream& operator<<(const vixl::aarch32::Register reg) OVERRIDE {
+ DisassemblerStream& operator<<(vixl::aarch32::Register reg) OVERRIDE {
if (reg.Is(tr)) {
os() << "tr";
return *this;
@@ -118,20 +116,11 @@
CustomDisassembler(std::ostream& os, const DisassemblerOptions* options)
: PrintDisassembler(&disassembler_stream_), disassembler_stream_(os, this, options) {}
- void PrintPc(uint32_t prog_ctr) OVERRIDE {
+ void PrintCodeAddress(uint32_t prog_ctr) OVERRIDE {
os() << "0x" << std::hex << std::setw(8) << std::setfill('0') << prog_ctr << ": ";
}
- bool IsT32() const {
- return is_t32_;
- }
-
- void SetT32(bool is_t32) {
- is_t32_ = is_t32;
- }
-
private:
- bool is_t32_;
CustomDisassemblerStream disassembler_stream_;
};
@@ -152,7 +141,7 @@
sizeof(unaligned_float), sizeof(unaligned_double)};
const uintptr_t begin = reinterpret_cast<uintptr_t>(options_->base_address_);
const uintptr_t end = reinterpret_cast<uintptr_t>(options_->end_address_);
- uintptr_t literal_addr = RoundDown(disasm_->GetPc(), vixl::aarch32::kRegSizeInBytes) + offset;
+ uintptr_t literal_addr = RoundDown(disasm_->GetCodeAddress(), vixl::aarch32::kRegSizeInBytes) + offset;
if (!options_->absolute_addresses_) {
literal_addr += begin;
@@ -208,12 +197,14 @@
// Remove the Thumb specifier bit; no effect if begin does not point to T32 code.
const uintptr_t instr_ptr = reinterpret_cast<uintptr_t>(begin) & ~1;
- disasm_->SetT32((reinterpret_cast<uintptr_t>(begin) & 1) != 0);
- disasm_->JumpToPc(GetPc(instr_ptr));
+ const bool is_t32 = (reinterpret_cast<uintptr_t>(begin) & 1) != 0;
+ disasm_->SetCodeAddress(GetPc(instr_ptr));
- if (disasm_->IsT32()) {
+ if (is_t32) {
const uint16_t* const ip = reinterpret_cast<const uint16_t*>(instr_ptr);
- next = reinterpret_cast<uintptr_t>(disasm_->DecodeT32At(ip));
+ const uint16_t* const end_address = reinterpret_cast<const uint16_t*>(
+ GetDisassemblerOptions()->end_address_);
+ next = reinterpret_cast<uintptr_t>(disasm_->DecodeT32At(ip, end_address));
} else {
const uint32_t* const ip = reinterpret_cast<const uint32_t*>(instr_ptr);
next = reinterpret_cast<uintptr_t>(disasm_->DecodeA32At(ip));
@@ -230,10 +221,10 @@
// Remove the Thumb specifier bit; no effect if begin does not point to T32 code.
const uintptr_t base = reinterpret_cast<uintptr_t>(begin) & ~1;
- disasm_->SetT32((reinterpret_cast<uintptr_t>(begin) & 1) != 0);
- disasm_->JumpToPc(GetPc(base));
+ const bool is_t32 = (reinterpret_cast<uintptr_t>(begin) & 1) != 0;
+ disasm_->SetCodeAddress(GetPc(base));
- if (disasm_->IsT32()) {
+ if (is_t32) {
// The Thumb specifier bits cancel each other.
disasm_->DisassembleT32Buffer(reinterpret_cast<const uint16_t*>(base), end - begin);
} else {
diff --git a/oatdump/Android.bp b/oatdump/Android.bp
index bbe6cc1..f1fcf3d 100644
--- a/oatdump/Android.bp
+++ b/oatdump/Android.bp
@@ -54,13 +54,22 @@
art_cc_binary {
name: "oatdumps",
- defaults: ["oatdump-defaults"],
device_supported: false,
+ static_executable: true,
+ defaults: ["oatdump-defaults"],
target: {
darwin: {
enabled: false,
},
},
+ ldflags: [
+ // We need this because GC stress mode makes use of
+ // _Unwind_GetIP and _Unwind_Backtrace and the symbols are also
+ // defined in libgcc_eh.a(unwind-dw2.o)
+ // TODO: Having this is not ideal as it might obscure errors.
+ // Try to get rid of it.
+ "-z muldefs",
+ ],
static_libs: [
"libart",
"libart-compiler",
@@ -72,16 +81,25 @@
art_cc_binary {
name: "oatdumpds",
+ device_supported: false,
+ static_executable: true,
defaults: [
"art_debug_defaults",
"oatdump-defaults",
],
- device_supported: false,
target: {
darwin: {
enabled: false,
},
},
+ ldflags: [
+ // We need this because GC stress mode makes use of
+ // _Unwind_GetIP and _Unwind_Backtrace and the symbols are also
+ // defined in libgcc_eh.a(unwind-dw2.o)
+ // TODO: Having this is not ideal as it might obscure errors.
+ // Try to get rid of it.
+ "-z muldefs",
+ ],
static_libs: [
"libartd",
"libartd-compiler",
diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc
index 3d208b5..3ad0f1e 100644
--- a/oatdump/oatdump.cc
+++ b/oatdump/oatdump.cc
@@ -794,7 +794,7 @@
uint32_t oat_class_offset = oat_dex_file.GetOatClassOffset(class_def_index);
const OatFile::OatClass oat_class = oat_dex_file.GetOatClass(class_def_index);
os << StringPrintf("%zd: %s (offset=0x%08x) (type_idx=%d)",
- class_def_index, descriptor, oat_class_offset, class_def.class_idx_)
+ class_def_index, descriptor, oat_class_offset, class_def.class_idx_.index_)
<< " (" << oat_class.GetStatus() << ")"
<< " (" << oat_class.GetType() << ")\n";
// TODO: include bitmap here if type is kOatClassSomeCompiled?
@@ -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/profman/profile_assistant_test.cc b/profman/profile_assistant_test.cc
index cd0aa6f..776c31a 100644
--- a/profman/profile_assistant_test.cc
+++ b/profman/profile_assistant_test.cc
@@ -42,7 +42,7 @@
ASSERT_TRUE(info->AddMethodIndex(dex_location2, dex_location_checksum2, i));
}
for (uint16_t i = 0; i < number_of_classes; i++) {
- ASSERT_TRUE(info->AddClassIndex(dex_location1, dex_location_checksum1, i));
+ ASSERT_TRUE(info->AddClassIndex(dex_location1, dex_location_checksum1, dex::TypeIndex(i)));
}
ASSERT_TRUE(info->Save(GetFd(profile)));
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/stub_test.cc b/runtime/arch/stub_test.cc
index bbf9a8b..6665897 100644
--- a/runtime/arch/stub_test.cc
+++ b/runtime/arch/stub_test.cc
@@ -1063,7 +1063,7 @@
EXPECT_FALSE(self->IsExceptionPending());
{
// Use an arbitrary method from c to use as referrer
- size_t result = Invoke3(static_cast<size_t>(c->GetDexTypeIndex()), // type_idx
+ size_t result = Invoke3(static_cast<size_t>(c->GetDexTypeIndex().index_), // type_idx
// arbitrary
reinterpret_cast<size_t>(c->GetVirtualMethod(0, kRuntimePointerSize)),
0U,
@@ -1197,7 +1197,7 @@
if ((false)) {
// Use an arbitrary method from c to use as referrer
size_t result = Invoke3(
- static_cast<size_t>(c->GetDexTypeIndex()), // type_idx
+ static_cast<size_t>(c->GetDexTypeIndex().index_), // type_idx
10U,
// arbitrary
reinterpret_cast<size_t>(c_obj->GetVirtualMethod(0, kRuntimePointerSize)),
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/art_field.cc b/runtime/art_field.cc
index b46b058..25b8ed2 100644
--- a/runtime/art_field.cc
+++ b/runtime/art_field.cc
@@ -48,7 +48,7 @@
return Runtime::Current()->GetClassLinker()->FindSystemClass(Thread::Current(), descriptor);
}
-ObjPtr<mirror::Class> ArtField::ResolveGetType(uint32_t type_idx) {
+ObjPtr<mirror::Class> ArtField::ResolveGetType(dex::TypeIndex type_idx) {
return Runtime::Current()->GetClassLinker()->ResolveType(type_idx, this);
}
diff --git a/runtime/art_field.h b/runtime/art_field.h
index 7c2f490..cacb324 100644
--- a/runtime/art_field.h
+++ b/runtime/art_field.h
@@ -19,6 +19,7 @@
#include <jni.h>
+#include "dex_file_types.h"
#include "gc_root.h"
#include "modifiers.h"
#include "obj_ptr.h"
@@ -216,7 +217,8 @@
private:
ObjPtr<mirror::Class> ProxyFindSystemClass(const char* descriptor)
REQUIRES_SHARED(Locks::mutator_lock_);
- ObjPtr<mirror::Class> ResolveGetType(uint32_t type_idx) REQUIRES_SHARED(Locks::mutator_lock_);
+ ObjPtr<mirror::Class> ResolveGetType(dex::TypeIndex type_idx)
+ REQUIRES_SHARED(Locks::mutator_lock_);
ObjPtr<mirror::String> ResolveGetStringName(Thread* self,
const DexFile& dex_file,
uint32_t string_idx,
diff --git a/runtime/art_method-inl.h b/runtime/art_method-inl.h
index a652178..2dfdc16 100644
--- a/runtime/art_method-inl.h
+++ b/runtime/art_method-inl.h
@@ -183,17 +183,17 @@
}
template <bool kWithCheck>
-inline mirror::Class* ArtMethod::GetDexCacheResolvedType(uint32_t type_index,
+inline mirror::Class* ArtMethod::GetDexCacheResolvedType(dex::TypeIndex type_index,
PointerSize pointer_size) {
if (kWithCheck) {
mirror::DexCache* dex_cache =
GetInterfaceMethodIfProxy(pointer_size)->GetDeclaringClass()->GetDexCache();
- if (UNLIKELY(type_index >= dex_cache->NumResolvedTypes())) {
- ThrowArrayIndexOutOfBoundsException(type_index, dex_cache->NumResolvedTypes());
+ if (UNLIKELY(type_index.index_ >= dex_cache->NumResolvedTypes())) {
+ ThrowArrayIndexOutOfBoundsException(type_index.index_, dex_cache->NumResolvedTypes());
return nullptr;
}
}
- mirror::Class* klass = GetDexCacheResolvedTypes(pointer_size)[type_index].Read();
+ mirror::Class* klass = GetDexCacheResolvedTypes(pointer_size)[type_index.index_].Read();
return (klass != nullptr && !klass->IsErroneous()) ? klass : nullptr;
}
@@ -210,7 +210,7 @@
return GetDexCacheResolvedTypes(pointer_size) == other->GetDexCacheResolvedTypes(pointer_size);
}
-inline mirror::Class* ArtMethod::GetClassFromTypeIndex(uint16_t type_idx,
+inline mirror::Class* ArtMethod::GetClassFromTypeIndex(dex::TypeIndex type_idx,
bool resolve,
PointerSize pointer_size) {
mirror::Class* type = GetDexCacheResolvedType(type_idx, pointer_size);
@@ -336,7 +336,7 @@
return GetDeclaringClass()->GetDexFile().GetCodeItem(GetCodeItemOffset());
}
-inline bool ArtMethod::IsResolvedTypeIdx(uint16_t type_idx, PointerSize pointer_size) {
+inline bool ArtMethod::IsResolvedTypeIdx(dex::TypeIndex type_idx, PointerSize pointer_size) {
DCHECK(!IsProxyMethod());
return GetDexCacheResolvedType(type_idx, pointer_size) != nullptr;
}
@@ -383,11 +383,10 @@
const DexFile* dex_file = GetDexFile();
const DexFile::MethodId& method_id = dex_file->GetMethodId(GetDexMethodIndex());
const DexFile::ProtoId& proto_id = dex_file->GetMethodPrototype(method_id);
- uint16_t return_type_idx = proto_id.return_type_idx_;
- return dex_file->GetTypeDescriptor(dex_file->GetTypeId(return_type_idx));
+ return dex_file->GetTypeDescriptor(dex_file->GetTypeId(proto_id.return_type_idx_));
}
-inline const char* ArtMethod::GetTypeDescriptorFromTypeIdx(uint16_t type_idx) {
+inline const char* ArtMethod::GetTypeDescriptorFromTypeIdx(dex::TypeIndex type_idx) {
DCHECK(!IsProxyMethod());
const DexFile* dex_file = GetDexFile();
return dex_file->GetTypeDescriptor(dex_file->GetTypeId(type_idx));
@@ -440,7 +439,7 @@
const DexFile* dex_file = GetDexFile();
const DexFile::MethodId& method_id = dex_file->GetMethodId(GetDexMethodIndex());
const DexFile::ProtoId& proto_id = dex_file->GetMethodPrototype(method_id);
- uint16_t return_type_idx = proto_id.return_type_idx_;
+ dex::TypeIndex return_type_idx = proto_id.return_type_idx_;
mirror::Class* type = GetDexCacheResolvedType(return_type_idx, pointer_size);
if (type == nullptr && resolve) {
type = Runtime::Current()->GetClassLinker()->ResolveType(return_type_idx, this);
diff --git a/runtime/art_method.cc b/runtime/art_method.cc
index c550a1b..d1454b6 100644
--- a/runtime/art_method.cc
+++ b/runtime/art_method.cc
@@ -199,9 +199,9 @@
// Iterate over the catch handlers associated with dex_pc.
PointerSize pointer_size = Runtime::Current()->GetClassLinker()->GetImagePointerSize();
for (CatchHandlerIterator it(*code_item, dex_pc); it.HasNext(); it.Next()) {
- uint16_t iter_type_idx = it.GetHandlerTypeIndex();
+ dex::TypeIndex iter_type_idx = it.GetHandlerTypeIndex();
// Catch all case
- if (iter_type_idx == DexFile::kDexNoIndex16) {
+ if (!iter_type_idx.IsValid()) {
found_dex_pc = it.GetHandlerAddress();
break;
}
@@ -476,7 +476,11 @@
}
// The table is in the .vdex file.
const OatFile::OatDexFile* oat_dex_file = GetDexCache()->GetDexFile()->GetOatDexFile();
- return oat_dex_file->GetOatFile()->DexBegin() + header->vmap_table_offset_;
+ const OatFile* oat_file = oat_dex_file->GetOatFile();
+ if (oat_file == nullptr) {
+ return nullptr;
+ }
+ return oat_file->DexBegin() + header->vmap_table_offset_;
} else {
return oat_method.GetVmapTable();
}
diff --git a/runtime/art_method.h b/runtime/art_method.h
index b31999f..0e1d7e7 100644
--- a/runtime/art_method.h
+++ b/runtime/art_method.h
@@ -343,7 +343,7 @@
REQUIRES_SHARED(Locks::mutator_lock_);
template <bool kWithCheck = true>
- mirror::Class* GetDexCacheResolvedType(uint32_t type_idx, PointerSize pointer_size)
+ mirror::Class* GetDexCacheResolvedType(dex::TypeIndex type_idx, PointerSize pointer_size)
REQUIRES_SHARED(Locks::mutator_lock_);
void SetDexCacheResolvedTypes(GcRoot<mirror::Class>* new_dex_cache_types,
PointerSize pointer_size)
@@ -355,7 +355,9 @@
REQUIRES_SHARED(Locks::mutator_lock_);
// Get the Class* from the type index into this method's dex cache.
- mirror::Class* GetClassFromTypeIndex(uint16_t type_idx, bool resolve, PointerSize pointer_size)
+ mirror::Class* GetClassFromTypeIndex(dex::TypeIndex type_idx,
+ bool resolve,
+ PointerSize pointer_size)
REQUIRES_SHARED(Locks::mutator_lock_);
// Returns true if this method has the same name and signature of the other method.
@@ -527,7 +529,7 @@
const DexFile::CodeItem* GetCodeItem() REQUIRES_SHARED(Locks::mutator_lock_);
- bool IsResolvedTypeIdx(uint16_t type_idx, PointerSize pointer_size)
+ bool IsResolvedTypeIdx(dex::TypeIndex type_idx, PointerSize pointer_size)
REQUIRES_SHARED(Locks::mutator_lock_);
int32_t GetLineNumFromDexPC(uint32_t dex_pc) REQUIRES_SHARED(Locks::mutator_lock_);
@@ -544,7 +546,7 @@
const char* GetReturnTypeDescriptor() REQUIRES_SHARED(Locks::mutator_lock_);
- const char* GetTypeDescriptorFromTypeIdx(uint16_t type_idx)
+ const char* GetTypeDescriptorFromTypeIdx(dex::TypeIndex type_idx)
REQUIRES_SHARED(Locks::mutator_lock_);
// May cause thread suspension due to GetClassFromTypeIdx calling ResolveType this caused a large
diff --git a/runtime/base/logging.cc b/runtime/base/logging.cc
index 6b21a56..1dca428 100644
--- a/runtime/base/logging.cc
+++ b/runtime/base/logging.cc
@@ -80,7 +80,7 @@
gCmdLine.reset(new std::string("<unset>"));
}
-#ifdef __ANDROID__
+#ifdef ART_TARGET_ANDROID
#define INIT_LOGGING_DEFAULT_LOGGER android::base::LogdLogger()
#else
#define INIT_LOGGING_DEFAULT_LOGGER android::base::StderrLogger
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/base/mutex.cc b/runtime/base/mutex.cc
index 5d92298..e8ef69f 100644
--- a/runtime/base/mutex.cc
+++ b/runtime/base/mutex.cc
@@ -48,7 +48,7 @@
Mutex* Locks::modify_ldt_lock_ = nullptr;
MutatorMutex* Locks::mutator_lock_ = nullptr;
Mutex* Locks::profiler_lock_ = nullptr;
-Mutex* Locks::verifier_deps_lock_ = nullptr;
+ReaderWriterMutex* Locks::verifier_deps_lock_ = nullptr;
ReaderWriterMutex* Locks::oat_file_manager_lock_ = nullptr;
Mutex* Locks::host_dlopen_handles_lock_ = nullptr;
Mutex* Locks::reference_processor_lock_ = nullptr;
@@ -672,7 +672,7 @@
ScopedContentionRecorder scr(this, GetExclusiveOwnerTid(), SafeGetTid(self));
++num_pending_readers_;
if (futex(state_.Address(), FUTEX_WAIT, cur_state, nullptr, nullptr, 0) != 0) {
- if (errno != EAGAIN) {
+ if (errno != EAGAIN && errno != EINTR) {
PLOG(FATAL) << "futex wait failed for " << name_;
}
}
@@ -796,7 +796,7 @@
reinterpret_cast<const timespec*>(std::numeric_limits<int32_t>::max()),
guard_.state_.Address(), cur_sequence) != -1;
if (!done) {
- if (errno != EAGAIN) {
+ if (errno != EAGAIN && errno != EINTR) {
PLOG(FATAL) << "futex cmp requeue failed for " << name_;
}
}
@@ -1039,7 +1039,7 @@
UPDATE_CURRENT_LOCK_LEVEL(kVerifierDepsLock);
DCHECK(verifier_deps_lock_ == nullptr);
- verifier_deps_lock_ = new Mutex("verifier deps lock", current_lock_level);
+ verifier_deps_lock_ = new ReaderWriterMutex("verifier deps lock", current_lock_level);
UPDATE_CURRENT_LOCK_LEVEL(kHostDlOpenHandlesLock);
DCHECK(host_dlopen_handles_lock_ == nullptr);
diff --git a/runtime/base/mutex.h b/runtime/base/mutex.h
index 74b786c..7e73e0d 100644
--- a/runtime/base/mutex.h
+++ b/runtime/base/mutex.h
@@ -658,8 +658,8 @@
// Guards opened oat files in OatFileManager.
static ReaderWriterMutex* oat_file_manager_lock_ ACQUIRED_AFTER(modify_ldt_lock_);
- // Guards verifier dependency collection in VerifierDeps.
- static Mutex* verifier_deps_lock_ ACQUIRED_AFTER(oat_file_manager_lock_);
+ // Guards extra string entries for VerifierDeps.
+ static ReaderWriterMutex* verifier_deps_lock_ ACQUIRED_AFTER(oat_file_manager_lock_);
// Guards dlopen_handles_ in DlOpenOatFile.
static Mutex* host_dlopen_handles_lock_ ACQUIRED_AFTER(verifier_deps_lock_);
diff --git a/runtime/base/stl_util.h b/runtime/base/stl_util.h
index a53dcea..d5f375a 100644
--- a/runtime/base/stl_util.h
+++ b/runtime/base/stl_util.h
@@ -18,6 +18,7 @@
#define ART_RUNTIME_BASE_STL_UTIL_H_
#include <algorithm>
+#include <set>
#include <sstream>
#include "base/logging.h"
@@ -187,6 +188,12 @@
using type = T;
};
+// Merge `other` entries into `to_update`.
+template <typename T>
+static inline void MergeSets(std::set<T>& to_update, const std::set<T>& other) {
+ to_update.insert(other.begin(), other.end());
+}
+
} // namespace art
#endif // ART_RUNTIME_BASE_STL_UTIL_H_
diff --git a/runtime/class_linker-inl.h b/runtime/class_linker-inl.h
index 350855b..81adaeb 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,
@@ -86,7 +86,7 @@
return string.Ptr();
}
-inline mirror::Class* ClassLinker::ResolveType(uint16_t type_idx, ArtMethod* referrer) {
+inline mirror::Class* ClassLinker::ResolveType(dex::TypeIndex type_idx, ArtMethod* referrer) {
Thread::PoisonObjectPointersIfDebug();
ObjPtr<mirror::Class> resolved_type =
referrer->GetDexCacheResolvedType(type_idx, image_pointer_size_);
@@ -103,7 +103,7 @@
return resolved_type.Ptr();
}
-inline mirror::Class* ClassLinker::ResolveType(uint16_t type_idx, ArtField* referrer) {
+inline mirror::Class* ClassLinker::ResolveType(dex::TypeIndex type_idx, ArtField* referrer) {
Thread::PoisonObjectPointersIfDebug();
ObjPtr<mirror::Class> declaring_class = referrer->GetDeclaringClass();
ObjPtr<mirror::DexCache> dex_cache_ptr = declaring_class->GetDexCache();
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index ac5e6aa..f3aba97 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -240,6 +240,12 @@
ScopedLocalRef<jthrowable> cause(env, env->ExceptionOccurred());
CHECK(cause.get() != nullptr);
+ // Boot classpath classes should not fail initialization.
+ if (!Runtime::Current()->IsAotCompiler()) {
+ std::string tmp;
+ CHECK(klass->GetClassLoader() != nullptr) << klass->GetDescriptor(&tmp);
+ }
+
env->ExceptionClear();
bool is_error = env->IsInstanceOf(cause.get(), WellKnownClasses::java_lang_Error);
env->Throw(cause.get());
@@ -475,6 +481,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));
@@ -727,10 +736,12 @@
const DexFile& dex_file = java_lang_Object->GetDexFile();
const DexFile::TypeId* void_type_id = dex_file.FindTypeId("V");
CHECK(void_type_id != nullptr);
- uint16_t void_type_idx = dex_file.GetIndexForTypeId(*void_type_id);
+ dex::TypeIndex void_type_idx = dex_file.GetIndexForTypeId(*void_type_id);
// Now we resolve void type so the dex cache contains it. We use java.lang.Object class
// as referrer so the used dex cache is core's one.
- ObjPtr<mirror::Class> resolved_type = ResolveType(dex_file, void_type_idx, java_lang_Object.Get());
+ ObjPtr<mirror::Class> resolved_type = ResolveType(dex_file,
+ void_type_idx,
+ java_lang_Object.Get());
CHECK_EQ(resolved_type, GetClassRoot(kPrimitiveVoid));
self->AssertNoPendingException();
}
@@ -916,13 +927,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 +3410,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 +3429,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();
}
@@ -3996,7 +4008,7 @@
const OatFile::OatDexFile* oat_dex_file = dex_file.GetOatDexFile();
// In case we run without an image there won't be a backing oat file.
- if (oat_dex_file == nullptr) {
+ if (oat_dex_file == nullptr || oat_dex_file->GetOatFile() == nullptr) {
return false;
}
@@ -4086,7 +4098,7 @@
for (; iterator.HasNext(); iterator.Next()) {
// Ensure exception types are resolved so that they don't need resolution to be delivered,
// unresolved exception types will be ignored by exception delivery
- if (iterator.GetHandlerTypeIndex() != DexFile::kDexNoIndex16) {
+ if (iterator.GetHandlerTypeIndex().IsValid()) {
ObjPtr<mirror::Class> exception_type = ResolveType(iterator.GetHandlerTypeIndex(), method);
if (exception_type == nullptr) {
DCHECK(Thread::Current()->IsExceptionPending());
@@ -4121,6 +4133,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());
@@ -4750,7 +4764,7 @@
const DexFile* dex_file = m->GetDexFile();
const DexFile::MethodId& method_id = dex_file->GetMethodId(m->GetDexMethodIndex());
const DexFile::ProtoId& proto_id = dex_file->GetMethodPrototype(method_id);
- uint16_t return_type_idx = proto_id.return_type_idx_;
+ dex::TypeIndex return_type_idx = proto_id.return_type_idx_;
std::string return_type = dex_file->PrettyType(return_type_idx);
std::string class_loader = mirror::Object::PrettyTypeOf(m->GetDeclaringClass()->GetClassLoader());
ThrowWrappedLinkageError(klass.Get(),
@@ -4768,7 +4782,7 @@
ArtMethod* method,
ArtMethod* m,
uint32_t index,
- uint32_t arg_type_idx)
+ dex::TypeIndex arg_type_idx)
REQUIRES_SHARED(Locks::mutator_lock_) {
DCHECK(Thread::Current()->IsExceptionPending());
DCHECK(!m->IsProxyMethod());
@@ -4858,7 +4872,7 @@
}
for (uint32_t i = 0; i < num_types; ++i) {
StackHandleScope<1> hs(self);
- uint32_t param_type_idx = types1->GetTypeItem(i).type_idx_;
+ dex::TypeIndex param_type_idx = types1->GetTypeItem(i).type_idx_;
Handle<mirror::Class> param_type(hs.NewHandle(
method1->GetClassFromTypeIndex(param_type_idx, true /* resolve */, pointer_size)));
if (UNLIKELY(param_type.Get() == nullptr)) {
@@ -4866,7 +4880,7 @@
method1, i, param_type_idx);
return false;
}
- uint32_t other_param_type_idx = types2->GetTypeItem(i).type_idx_;
+ dex::TypeIndex other_param_type_idx = types2->GetTypeItem(i).type_idx_;
ObjPtr<mirror::Class> other_param_type =
method2->GetClassFromTypeIndex(other_param_type_idx, true /* resolve */, pointer_size);
if (UNLIKELY(other_param_type == nullptr)) {
@@ -5350,8 +5364,8 @@
bool ClassLinker::LoadSuperAndInterfaces(Handle<mirror::Class> klass, const DexFile& dex_file) {
CHECK_EQ(mirror::Class::kStatusIdx, klass->GetStatus());
const DexFile::ClassDef& class_def = dex_file.GetClassDef(klass->GetDexClassDefIndex());
- uint16_t super_class_idx = class_def.superclass_idx_;
- if (super_class_idx != DexFile::kDexNoIndex16) {
+ dex::TypeIndex super_class_idx = class_def.superclass_idx_;
+ if (super_class_idx.IsValid()) {
// Check that a class does not inherit from itself directly.
//
// TODO: This is a cheap check to detect the straightforward case
@@ -5388,7 +5402,7 @@
const DexFile::TypeList* interfaces = dex_file.GetInterfacesList(class_def);
if (interfaces != nullptr) {
for (size_t i = 0; i < interfaces->Size(); i++) {
- uint16_t idx = interfaces->GetTypeItem(i).type_idx_;
+ dex::TypeIndex idx = interfaces->GetTypeItem(i).type_idx_;
ObjPtr<mirror::Class> interface = ResolveType(dex_file, idx, klass.Get());
if (interface == nullptr) {
DCHECK(Thread::Current()->IsExceptionPending());
@@ -6381,16 +6395,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 +6599,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,
@@ -7502,7 +7518,7 @@
}
ObjPtr<mirror::Class> ClassLinker::LookupResolvedType(const DexFile& dex_file,
- uint16_t type_idx,
+ dex::TypeIndex type_idx,
ObjPtr<mirror::DexCache> dex_cache,
ObjPtr<mirror::ClassLoader> class_loader) {
ObjPtr<mirror::Class> type = dex_cache->GetResolvedType(type_idx);
@@ -7528,7 +7544,7 @@
}
mirror::Class* ClassLinker::ResolveType(const DexFile& dex_file,
- uint16_t type_idx,
+ dex::TypeIndex type_idx,
ObjPtr<mirror::Class> referrer) {
StackHandleScope<2> hs(Thread::Current());
Handle<mirror::DexCache> dex_cache(hs.NewHandle(referrer->GetDexCache()));
@@ -7537,7 +7553,7 @@
}
mirror::Class* ClassLinker::ResolveType(const DexFile& dex_file,
- uint16_t type_idx,
+ dex::TypeIndex type_idx,
Handle<mirror::DexCache> dex_cache,
Handle<mirror::ClassLoader> class_loader) {
DCHECK(dex_cache.Get() != nullptr);
@@ -7931,7 +7947,7 @@
int32_t i = 0;
MutableHandle<mirror::Class> param_class = hs.NewHandle<mirror::Class>(nullptr);
for (; it.HasNext(); it.Next()) {
- const uint16_t type_idx = it.GetTypeIdx();
+ const dex::TypeIndex type_idx = it.GetTypeIdx();
param_class.Assign(ResolveType(dex_file, type_idx, dex_cache, class_loader));
if (param_class.Get() == nullptr) {
DCHECK(self->IsExceptionPending());
@@ -8342,10 +8358,10 @@
dex_file->GetBaseLocation(),
dex_file->GetLocationChecksum());
size_t num_resolved = 0;
- std::unordered_set<uint16_t> class_set;
+ std::unordered_set<dex::TypeIndex> class_set;
CHECK_EQ(num_types, dex_cache->NumResolvedTypes());
for (size_t i = 0; i < num_types; ++i) {
- ObjPtr<mirror::Class> klass = dex_cache->GetResolvedType(i);
+ ObjPtr<mirror::Class> klass = dex_cache->GetResolvedType(dex::TypeIndex(i));
// Filter out null class loader since that is the boot class loader.
if (klass == nullptr || (ignore_boot_classes && klass->GetClassLoader() == nullptr)) {
continue;
@@ -8358,17 +8374,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 +8426,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 (dex::TypeIndex 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.h b/runtime/class_linker.h
index 1d29e31..9563448 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -32,6 +32,7 @@
#include "class_table.h"
#include "dex_cache_resolved_classes.h"
#include "dex_file.h"
+#include "dex_file_types.h"
#include "gc_root.h"
#include "jni.h"
#include "mirror/class.h"
@@ -255,7 +256,7 @@
// result in the DexCache. The referrer is used to identify the
// target DexCache and ClassLoader to use for resolution.
mirror::Class* ResolveType(const DexFile& dex_file,
- uint16_t type_idx,
+ dex::TypeIndex type_idx,
ObjPtr<mirror::Class> referrer)
REQUIRES_SHARED(Locks::mutator_lock_)
REQUIRES(!dex_lock_, !Roles::uninterruptible_);
@@ -263,18 +264,18 @@
// Resolve a Type with the given index from the DexFile, storing the
// result in the DexCache. The referrer is used to identify the
// target DexCache and ClassLoader to use for resolution.
- mirror::Class* ResolveType(uint16_t type_idx, ArtMethod* referrer)
+ mirror::Class* ResolveType(dex::TypeIndex type_idx, ArtMethod* referrer)
REQUIRES_SHARED(Locks::mutator_lock_)
REQUIRES(!dex_lock_, !Roles::uninterruptible_);
- mirror::Class* ResolveType(uint16_t type_idx, ArtField* referrer)
+ mirror::Class* ResolveType(dex::TypeIndex type_idx, ArtField* referrer)
REQUIRES_SHARED(Locks::mutator_lock_)
REQUIRES(!dex_lock_, !Roles::uninterruptible_);
// Look up a resolved type with the given ID from the DexFile. The ClassLoader is used to search
// for the type, since it may be referenced from but not contained within the given DexFile.
ObjPtr<mirror::Class> LookupResolvedType(const DexFile& dex_file,
- uint16_t type_idx,
+ dex::TypeIndex type_idx,
ObjPtr<mirror::DexCache> dex_cache,
ObjPtr<mirror::ClassLoader> class_loader)
REQUIRES_SHARED(Locks::mutator_lock_);
@@ -284,7 +285,7 @@
// type, since it may be referenced from but not contained within
// the given DexFile.
mirror::Class* ResolveType(const DexFile& dex_file,
- uint16_t type_idx,
+ dex::TypeIndex type_idx,
Handle<mirror::DexCache> dex_cache,
Handle<mirror::ClassLoader> class_loader)
REQUIRES_SHARED(Locks::mutator_lock_)
diff --git a/runtime/class_linker_test.cc b/runtime/class_linker_test.cc
index ab2d9d0..9e17be2 100644
--- a/runtime/class_linker_test.cc
+++ b/runtime/class_linker_test.cc
@@ -25,6 +25,7 @@
#include "class_linker-inl.h"
#include "common_runtime_test.h"
#include "dex_file.h"
+#include "dex_file_types.h"
#include "experimental_flags.h"
#include "entrypoints/entrypoint_utils-inl.h"
#include "gc/heap.h"
@@ -101,7 +102,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());
}
@@ -428,7 +430,7 @@
}
// Verify all the types referenced by this file
for (size_t i = 0; i < dex.NumTypeIds(); i++) {
- const DexFile::TypeId& type_id = dex.GetTypeId(i);
+ const DexFile::TypeId& type_id = dex.GetTypeId(dex::TypeIndex(i));
const char* descriptor = dex.GetTypeDescriptor(type_id);
AssertDexFileClass(class_loader, descriptor);
}
@@ -890,7 +892,7 @@
hs.NewHandle(soa.Decode<mirror::ClassLoader>(LoadDex("MyClass"))));
AssertNonExistentClass("LMyClass;");
ObjPtr<mirror::Class> klass = class_linker_->FindClass(soa.Self(), "LMyClass;", class_loader);
- uint32_t type_idx = klass->GetClassDef()->class_idx_;
+ dex::TypeIndex type_idx = klass->GetClassDef()->class_idx_;
ObjPtr<mirror::DexCache> dex_cache = klass->GetDexCache();
const DexFile& dex_file = klass->GetDexFile();
EXPECT_OBJ_PTR_EQ(dex_cache->GetResolvedType(type_idx), klass);
@@ -1153,7 +1155,7 @@
ArtMethod* getS0 = klass->FindDirectMethod("getS0", "()Ljava/lang/Object;", kRuntimePointerSize);
const DexFile::TypeId* type_id = dex_file->FindTypeId("LStaticsFromCode;");
ASSERT_TRUE(type_id != nullptr);
- uint32_t type_idx = dex_file->GetIndexForTypeId(*type_id);
+ dex::TypeIndex type_idx = dex_file->GetIndexForTypeId(*type_id);
mirror::Class* uninit = ResolveVerifyAndClinit(type_idx, clinit, soa.Self(), true, false);
EXPECT_TRUE(uninit != nullptr);
EXPECT_FALSE(uninit->IsInitialized());
diff --git a/runtime/class_table.cc b/runtime/class_table.cc
index b44104e..0fcce6b 100644
--- a/runtime/class_table.cc
+++ b/runtime/class_table.cc
@@ -170,7 +170,7 @@
const DexFile* dex_file = ObjPtr<mirror::DexCache>::DownCast(obj)->GetDexFile();
if (dex_file != nullptr && dex_file->GetOatDexFile() != nullptr) {
const OatFile* oat_file = dex_file->GetOatDexFile()->GetOatFile();
- if (!oat_file->GetBssGcRoots().empty()) {
+ if (oat_file != nullptr && !oat_file->GetBssGcRoots().empty()) {
InsertOatFileLocked(oat_file); // Ignore return value.
}
}
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/compiler_filter.cc b/runtime/compiler_filter.cc
index dc197c1..6e3e1d8 100644
--- a/runtime/compiler_filter.cc
+++ b/runtime/compiler_filter.cc
@@ -33,6 +33,7 @@
case CompilerFilter::kTime:
case CompilerFilter::kSpeedProfile:
case CompilerFilter::kSpeed:
+ case CompilerFilter::kLayoutProfile:
case CompilerFilter::kEverythingProfile:
case CompilerFilter::kEverything: return true;
}
@@ -52,6 +53,7 @@
case CompilerFilter::kTime:
case CompilerFilter::kSpeedProfile:
case CompilerFilter::kSpeed:
+ case CompilerFilter::kLayoutProfile:
case CompilerFilter::kEverythingProfile:
case CompilerFilter::kEverything: return true;
}
@@ -71,6 +73,7 @@
case CompilerFilter::kTime:
case CompilerFilter::kSpeedProfile:
case CompilerFilter::kSpeed:
+ case CompilerFilter::kLayoutProfile:
case CompilerFilter::kEverythingProfile:
case CompilerFilter::kEverything: return true;
}
@@ -97,6 +100,7 @@
case CompilerFilter::kVerifyProfile:
case CompilerFilter::kSpaceProfile:
case CompilerFilter::kSpeedProfile:
+ case CompilerFilter::kLayoutProfile:
case CompilerFilter::kEverythingProfile: return true;
}
UNREACHABLE();
@@ -121,6 +125,7 @@
return CompilerFilter::kSpace;
case CompilerFilter::kSpeedProfile:
+ case CompilerFilter::kLayoutProfile:
return CompilerFilter::kSpeed;
case CompilerFilter::kEverythingProfile:
@@ -146,6 +151,7 @@
case CompilerFilter::kTime: return "time";
case CompilerFilter::kSpeedProfile: return "speed-profile";
case CompilerFilter::kSpeed: return "speed";
+ case CompilerFilter::kLayoutProfile: return "layout-profile";
case CompilerFilter::kEverythingProfile: return "everything-profile";
case CompilerFilter::kEverything: return "everything";
}
@@ -173,6 +179,8 @@
*filter = kSpeed;
} else if (strcmp(option, "speed-profile") == 0) {
*filter = kSpeedProfile;
+ } else if (strcmp(option, "layout-profile") == 0) {
+ *filter = kLayoutProfile;
} else if (strcmp(option, "everything") == 0) {
*filter = kEverything;
} else if (strcmp(option, "everything-profile") == 0) {
diff --git a/runtime/compiler_filter.h b/runtime/compiler_filter.h
index 37631cc..781d43a 100644
--- a/runtime/compiler_filter.h
+++ b/runtime/compiler_filter.h
@@ -39,6 +39,7 @@
kSpace, // Maximize space savings.
kBalanced, // Good performance return on compilation investment.
kSpeedProfile, // Maximize runtime performance based on profile.
+ kLayoutProfile, // Temporary filter for dexlayout. Will be merged with kSpeedProfile.
kSpeed, // Maximize runtime performance.
kEverythingProfile, // Compile everything capable of being compiled based on profile.
kEverything, // Compile everything capable of being compiled.
diff --git a/runtime/dex2oat_environment_test.h b/runtime/dex2oat_environment_test.h
index d717ec0..b0c4597 100644
--- a/runtime/dex2oat_environment_test.h
+++ b/runtime/dex2oat_environment_test.h
@@ -136,7 +136,9 @@
+ "/core.art";
}
- bool GetCachedImageFile(/*out*/std::string* image, std::string* error_msg) const {
+ bool GetCachedImageFile(const std::string& image_location,
+ /*out*/std::string* image,
+ /*out*/std::string* error_msg) const {
std::string cache;
bool have_android_data;
bool dalvik_cache_exists;
@@ -151,7 +153,14 @@
*error_msg = "Failed to create dalvik cache";
return false;
}
- return GetDalvikCacheFilename(GetImageLocation().c_str(), cache.c_str(), image, error_msg);
+ return GetDalvikCacheFilename(image_location.c_str(), cache.c_str(), image, error_msg);
+ }
+
+ // Returns the path to an image location whose contents differ from the
+ // image at GetImageLocation(). This is used for testing mismatched
+ // image checksums in the oat_file_assistant_tests.
+ std::string GetImageLocation2() const {
+ return GetImageDirectory() + "/core-npic.art";
}
std::string GetDexSrc1() const {
diff --git a/runtime/dex_cache_resolved_classes.h b/runtime/dex_cache_resolved_classes.h
index 0febbed..f53ca4a 100644
--- a/runtime/dex_cache_resolved_classes.h
+++ b/runtime/dex_cache_resolved_classes.h
@@ -21,6 +21,8 @@
#include <unordered_set>
#include <vector>
+#include "dex_file_types.h"
+
namespace art {
// Data structure for passing around which classes belonging to a dex cache / dex file are resolved.
@@ -59,7 +61,7 @@
return location_checksum_;
}
- const std::unordered_set<uint16_t>& GetClasses() const {
+ const std::unordered_set<dex::TypeIndex>& GetClasses() const {
return classes_;
}
@@ -68,7 +70,7 @@
const std::string base_location_;
const uint32_t location_checksum_;
// Array of resolved class def indexes.
- mutable std::unordered_set<uint16_t> classes_;
+ mutable std::unordered_set<dex::TypeIndex> classes_;
};
inline bool operator<(const DexCacheResolvedClasses& a, const DexCacheResolvedClasses& b) {
diff --git a/runtime/dex_file-inl.h b/runtime/dex_file-inl.h
index 621b2c5..77a63c1 100644
--- a/runtime/dex_file-inl.h
+++ b/runtime/dex_file-inl.h
@@ -58,12 +58,12 @@
return StringDataAndUtf16LengthByIdx(idx, &unicode_length);
}
-inline const char* DexFile::StringByTypeIdx(uint32_t idx, uint32_t* unicode_length) const {
+inline const char* DexFile::StringByTypeIdx(dex::TypeIndex idx, uint32_t* unicode_length) const {
const TypeId& type_id = GetTypeId(idx);
return StringDataAndUtf16LengthByIdx(type_id.descriptor_idx_, unicode_length);
}
-inline const char* DexFile::StringByTypeIdx(uint32_t idx) const {
+inline const char* DexFile::StringByTypeIdx(dex::TypeIndex idx) const {
const TypeId& type_id = GetTypeId(idx);
return StringDataByIdx(type_id.descriptor_idx_);
}
diff --git a/runtime/dex_file.cc b/runtime/dex_file.cc
index 2ef7509..cc544fd 100644
--- a/runtime/dex_file.cc
+++ b/runtime/dex_file.cc
@@ -26,6 +26,7 @@
#include <memory>
#include <sstream>
+#include <type_traits>
#include "base/enums.h"
#include "base/file_magic.h"
@@ -44,6 +45,9 @@
namespace art {
+static_assert(sizeof(dex::TypeIndex) == sizeof(uint16_t), "TypeIndex size is wrong");
+static_assert(std::is_trivially_copyable<dex::TypeIndex>::value, "TypeIndex not trivial");
+
static constexpr OatDexFile* kNoOatDexFile = nullptr;
const char* DexFile::kClassesDex = "classes.dex";
@@ -550,7 +554,7 @@
return atoi(version);
}
-const DexFile::ClassDef* DexFile::FindClassDef(uint16_t type_idx) const {
+const DexFile::ClassDef* DexFile::FindClassDef(dex::TypeIndex type_idx) const {
size_t num_class_defs = NumClassDefs();
// Fast path for rare no class defs case.
if (num_class_defs == 0) {
@@ -597,9 +601,9 @@
const DexFile::StringId& name,
const DexFile::TypeId& type) const {
// Binary search MethodIds knowing that they are sorted by class_idx, name_idx then proto_idx
- const uint16_t class_idx = GetIndexForTypeId(declaring_klass);
+ const dex::TypeIndex class_idx = GetIndexForTypeId(declaring_klass);
const uint32_t name_idx = GetIndexForStringId(name);
- const uint16_t type_idx = GetIndexForTypeId(type);
+ const dex::TypeIndex type_idx = GetIndexForTypeId(type);
int32_t lo = 0;
int32_t hi = NumFieldIds() - 1;
while (hi >= lo) {
@@ -632,7 +636,7 @@
const DexFile::StringId& name,
const DexFile::ProtoId& signature) const {
// Binary search MethodIds knowing that they are sorted by class_idx, name_idx then proto_idx
- const uint16_t class_idx = GetIndexForTypeId(declaring_klass);
+ const dex::TypeIndex class_idx = GetIndexForTypeId(declaring_klass);
const uint32_t name_idx = GetIndexForStringId(name);
const uint16_t proto_idx = GetIndexForProtoId(signature);
int32_t lo = 0;
@@ -687,7 +691,7 @@
int32_t hi = NumTypeIds() - 1;
while (hi >= lo) {
int32_t mid = (hi + lo) / 2;
- const TypeId& type_id = GetTypeId(mid);
+ const TypeId& type_id = GetTypeId(dex::TypeIndex(mid));
const DexFile::StringId& str_id = GetStringId(type_id.descriptor_idx_);
const char* str = GetStringData(str_id);
int compare = CompareModifiedUtf8ToModifiedUtf8AsUtf16CodePointValues(string, str);
@@ -726,7 +730,7 @@
int32_t hi = NumTypeIds() - 1;
while (hi >= lo) {
int32_t mid = (hi + lo) / 2;
- const TypeId& type_id = GetTypeId(mid);
+ const TypeId& type_id = GetTypeId(dex::TypeIndex(mid));
if (string_idx > type_id.descriptor_idx_) {
lo = mid + 1;
} else if (string_idx < type_id.descriptor_idx_) {
@@ -738,20 +742,20 @@
return nullptr;
}
-const DexFile::ProtoId* DexFile::FindProtoId(uint16_t return_type_idx,
- const uint16_t* signature_type_idxs,
+const DexFile::ProtoId* DexFile::FindProtoId(dex::TypeIndex return_type_idx,
+ const dex::TypeIndex* signature_type_idxs,
uint32_t signature_length) const {
int32_t lo = 0;
int32_t hi = NumProtoIds() - 1;
while (hi >= lo) {
int32_t mid = (hi + lo) / 2;
const DexFile::ProtoId& proto = GetProtoId(mid);
- int compare = return_type_idx - proto.return_type_idx_;
+ int compare = return_type_idx.index_ - proto.return_type_idx_.index_;
if (compare == 0) {
DexFileParameterIterator it(*this, proto);
size_t i = 0;
while (it.HasNext() && i < signature_length && compare == 0) {
- compare = signature_type_idxs[i] - it.GetTypeIdx();
+ compare = signature_type_idxs[i].index_ - it.GetTypeIdx().index_;
it.Next();
i++;
}
@@ -775,8 +779,9 @@
}
// Given a signature place the type ids into the given vector
-bool DexFile::CreateTypeList(const StringPiece& signature, uint16_t* return_type_idx,
- std::vector<uint16_t>* param_type_idxs) const {
+bool DexFile::CreateTypeList(const StringPiece& signature,
+ dex::TypeIndex* return_type_idx,
+ std::vector<dex::TypeIndex>* param_type_idxs) const {
if (signature[0] != '(') {
return false;
}
@@ -813,7 +818,7 @@
if (type_id == nullptr) {
return false;
}
- uint16_t type_idx = GetIndexForTypeId(*type_id);
+ dex::TypeIndex type_idx = GetIndexForTypeId(*type_id);
if (!process_return) {
param_type_idxs->push_back(type_idx);
} else {
@@ -825,8 +830,8 @@
}
const Signature DexFile::CreateSignature(const StringPiece& signature) const {
- uint16_t return_type_idx;
- std::vector<uint16_t> param_type_indices;
+ dex::TypeIndex return_type_idx;
+ std::vector<dex::TypeIndex> param_type_indices;
bool success = CreateTypeList(signature, &return_type_idx, ¶m_type_indices);
if (!success) {
return Signature::NoSignature();
@@ -971,7 +976,8 @@
}
local_in_reg[reg].name_ = StringDataByIdx(name_idx);
- local_in_reg[reg].descriptor_ = StringByTypeIdx(descriptor_idx);
+ local_in_reg[reg].descriptor_ =
+ StringByTypeIdx(dex::TypeIndex(dchecked_integral_cast<uint16_t>(descriptor_idx)));;
local_in_reg[reg].signature_ = StringDataByIdx(signature_idx);
local_in_reg[reg].start_address_ = address;
local_in_reg[reg].reg_ = reg;
@@ -1225,9 +1231,9 @@
return result;
}
-std::string DexFile::PrettyType(uint32_t type_idx) const {
- if (type_idx >= NumTypeIds()) {
- return StringPrintf("<<invalid-type-idx-%d>>", type_idx);
+std::string DexFile::PrettyType(dex::TypeIndex type_idx) const {
+ if (type_idx.index_ >= NumTypeIds()) {
+ return StringPrintf("<<invalid-type-idx-%d>>", type_idx.index_);
}
const DexFile::TypeId& type_id = GetTypeId(type_idx);
return PrettyDescriptor(GetTypeDescriptor(type_id));
@@ -1457,14 +1463,14 @@
void CatchHandlerIterator::Next() {
if (remaining_count_ > 0) {
- handler_.type_idx_ = DecodeUnsignedLeb128(¤t_data_);
+ handler_.type_idx_ = dex::TypeIndex(DecodeUnsignedLeb128(¤t_data_));
handler_.address_ = DecodeUnsignedLeb128(¤t_data_);
remaining_count_--;
return;
}
if (catch_all_) {
- handler_.type_idx_ = DexFile::kDexNoIndex16;
+ handler_.type_idx_ = dex::TypeIndex(DexFile::kDexNoIndex16);
handler_.address_ = DecodeUnsignedLeb128(¤t_data_);
catch_all_ = false;
return;
@@ -1474,4 +1480,13 @@
remaining_count_ = -1;
}
+namespace dex {
+
+std::ostream& operator<<(std::ostream& os, const TypeIndex& index) {
+ os << "TypeIndex[" << index.index_ << "]";
+ return os;
+}
+
+} // namespace dex
+
} // namespace art
diff --git a/runtime/dex_file.h b/runtime/dex_file.h
index da9fa50..2384eb6 100644
--- a/runtime/dex_file.h
+++ b/runtime/dex_file.h
@@ -23,6 +23,7 @@
#include "base/logging.h"
#include "base/value_object.h"
+#include "dex_file_types.h"
#include "globals.h"
#include "invoke_type.h"
#include "jni.h"
@@ -159,17 +160,28 @@
// Raw field_id_item.
struct FieldId {
- uint16_t class_idx_; // index into type_ids_ array for defining class
- uint16_t type_idx_; // index into type_ids_ array for field type
+ dex::TypeIndex class_idx_; // index into type_ids_ array for defining class
+ dex::TypeIndex type_idx_; // index into type_ids_ array for field type
uint32_t name_idx_; // index into string_ids_ array for field name
private:
DISALLOW_COPY_AND_ASSIGN(FieldId);
};
+ // Raw proto_id_item.
+ struct ProtoId {
+ uint32_t shorty_idx_; // index into string_ids array for shorty descriptor
+ dex::TypeIndex return_type_idx_; // index into type_ids array for return type
+ uint16_t pad_; // padding = 0
+ uint32_t parameters_off_; // file offset to type_list for parameter types
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ProtoId);
+ };
+
// Raw method_id_item.
struct MethodId {
- uint16_t class_idx_; // index into type_ids_ array for defining class
+ dex::TypeIndex class_idx_; // index into type_ids_ array for defining class
uint16_t proto_idx_; // index into proto_ids_ array for method prototype
uint32_t name_idx_; // index into string_ids_ array for method name
@@ -177,23 +189,12 @@
DISALLOW_COPY_AND_ASSIGN(MethodId);
};
- // Raw proto_id_item.
- struct ProtoId {
- uint32_t shorty_idx_; // index into string_ids array for shorty descriptor
- uint16_t return_type_idx_; // index into type_ids array for return type
- uint16_t pad_; // padding = 0
- uint32_t parameters_off_; // file offset to type_list for parameter types
-
- private:
- DISALLOW_COPY_AND_ASSIGN(ProtoId);
- };
-
// Raw class_def_item.
struct ClassDef {
- uint16_t class_idx_; // index into type_ids_ array for this class
+ dex::TypeIndex class_idx_; // index into type_ids_ array for this class
uint16_t pad1_; // padding = 0
uint32_t access_flags_;
- uint16_t superclass_idx_; // index into type_ids_ array for superclass
+ dex::TypeIndex superclass_idx_; // index into type_ids_ array for superclass
uint16_t pad2_; // padding = 0
uint32_t interfaces_off_; // file offset to TypeList
uint32_t source_file_idx_; // index into string_ids_ for source file name
@@ -225,7 +226,7 @@
// Raw type_item.
struct TypeItem {
- uint16_t type_idx_; // index into type_ids section
+ dex::TypeIndex type_idx_; // index into type_ids section
private:
DISALLOW_COPY_AND_ASSIGN(TypeItem);
@@ -540,23 +541,23 @@
}
// Returns the TypeId at the specified index.
- const TypeId& GetTypeId(uint32_t idx) const {
- DCHECK_LT(idx, NumTypeIds()) << GetLocation();
- return type_ids_[idx];
+ const TypeId& GetTypeId(dex::TypeIndex idx) const {
+ DCHECK_LT(idx.index_, NumTypeIds()) << GetLocation();
+ return type_ids_[idx.index_];
}
- uint16_t GetIndexForTypeId(const TypeId& type_id) const {
+ dex::TypeIndex GetIndexForTypeId(const TypeId& type_id) const {
CHECK_GE(&type_id, type_ids_) << GetLocation();
CHECK_LT(&type_id, type_ids_ + header_->type_ids_size_) << GetLocation();
size_t result = &type_id - type_ids_;
DCHECK_LT(result, 65536U) << GetLocation();
- return static_cast<uint16_t>(result);
+ return dex::TypeIndex(static_cast<uint16_t>(result));
}
// Get the descriptor string associated with a given type index.
- const char* StringByTypeIdx(uint32_t idx, uint32_t* unicode_length) const;
+ const char* StringByTypeIdx(dex::TypeIndex idx, uint32_t* unicode_length) const;
- const char* StringByTypeIdx(uint32_t idx) const;
+ const char* StringByTypeIdx(dex::TypeIndex idx) const;
// Returns the type descriptor string of a type id.
const char* GetTypeDescriptor(const TypeId& type_id) const;
@@ -671,7 +672,7 @@
const char* GetClassDescriptor(const ClassDef& class_def) const;
// Looks up a class definition by its type index.
- const ClassDef* FindClassDef(uint16_t type_idx) const;
+ const ClassDef* FindClassDef(dex::TypeIndex type_idx) const;
const TypeList* GetInterfacesList(const ClassDef& class_def) const {
if (class_def.interfaces_off_ == 0) {
@@ -711,7 +712,7 @@
}
// Returns the ProtoId at the specified index.
- const ProtoId& GetProtoId(uint32_t idx) const {
+ const ProtoId& GetProtoId(uint16_t idx) const {
DCHECK_LT(idx, NumProtoIds()) << GetLocation();
return proto_ids_[idx];
}
@@ -723,16 +724,18 @@
}
// Looks up a proto id for a given return type and signature type list
- const ProtoId* FindProtoId(uint16_t return_type_idx,
- const uint16_t* signature_type_idxs, uint32_t signature_length) const;
- const ProtoId* FindProtoId(uint16_t return_type_idx,
- const std::vector<uint16_t>& signature_type_idxs) const {
+ const ProtoId* FindProtoId(dex::TypeIndex return_type_idx,
+ const dex::TypeIndex* signature_type_idxs,
+ uint32_t signature_length) const;
+ const ProtoId* FindProtoId(dex::TypeIndex return_type_idx,
+ const std::vector<dex::TypeIndex>& signature_type_idxs) const {
return FindProtoId(return_type_idx, &signature_type_idxs[0], signature_type_idxs.size());
}
// Given a signature place the type ids into the given vector, returns true on success
- bool CreateTypeList(const StringPiece& signature, uint16_t* return_type_idx,
- std::vector<uint16_t>* param_type_idxs) const;
+ bool CreateTypeList(const StringPiece& signature,
+ dex::TypeIndex* return_type_idx,
+ std::vector<dex::TypeIndex>* param_type_idxs) const;
// Create a Signature from the given string signature or return Signature::NoSignature if not
// possible.
@@ -1010,6 +1013,11 @@
return oat_dex_file_;
}
+ // Used by oat writer.
+ void SetOatDexFile(OatDexFile* oat_dex_file) const {
+ oat_dex_file_ = oat_dex_file;
+ }
+
// Utility methods for reading integral values from a buffer.
static int32_t ReadSignedInt(const uint8_t* ptr, int zwidth);
static uint32_t ReadUnsignedInt(const uint8_t* ptr, int zwidth, bool fill_on_right);
@@ -1021,7 +1029,7 @@
// Returns a human-readable form of the field at an index.
std::string PrettyField(uint32_t field_idx, bool with_type = true) const;
// Returns a human-readable form of the type at an index.
- std::string PrettyType(uint32_t type_idx) const;
+ std::string PrettyType(dex::TypeIndex type_idx) const;
private:
static std::unique_ptr<const DexFile> OpenFile(int fd,
@@ -1138,9 +1146,10 @@
// If this dex file was loaded from an oat file, oat_dex_file_ contains a
// pointer to the OatDexFile it was loaded from. Otherwise oat_dex_file_ is
// null.
- const OatDexFile* oat_dex_file_;
+ mutable const OatDexFile* oat_dex_file_;
friend class DexFileVerifierTest;
+ friend class OatWriter;
ART_FRIEND_TEST(ClassLinkerTest, RegisterDexFileName); // for constructor
};
@@ -1165,11 +1174,11 @@
bool HasNext() const { return pos_ < size_; }
size_t Size() const { return size_; }
void Next() { ++pos_; }
- uint16_t GetTypeIdx() {
+ dex::TypeIndex GetTypeIdx() {
return type_list_->GetTypeItem(pos_).type_idx_;
}
const char* GetDescriptor() {
- return dex_file_.StringByTypeIdx(GetTypeIdx());
+ return dex_file_.StringByTypeIdx(dex::TypeIndex(GetTypeIdx()));
}
private:
const DexFile& dex_file_;
@@ -1455,7 +1464,7 @@
Init(handler_data);
}
- uint16_t GetHandlerTypeIndex() const {
+ dex::TypeIndex GetHandlerTypeIndex() const {
return handler_.type_idx_;
}
uint32_t GetHandlerAddress() const {
@@ -1476,7 +1485,7 @@
void Init(const uint8_t* handler_data);
struct CatchHandlerItem {
- uint16_t type_idx_; // type index of the caught exception type
+ dex::TypeIndex type_idx_; // type index of the caught exception type
uint32_t address_; // handler address
} handler_;
const uint8_t* current_data_; // the current handler in dex file.
diff --git a/runtime/dex_file_annotations.cc b/runtime/dex_file_annotations.cc
index 835f456..3fe2c40 100644
--- a/runtime/dex_file_annotations.cc
+++ b/runtime/dex_file_annotations.cc
@@ -90,7 +90,7 @@
const uint8_t* annotation = annotation_item->annotation_;
uint32_t type_index = DecodeUnsignedLeb128(&annotation);
- if (strcmp(descriptor, dex_file.StringByTypeIdx(type_index)) == 0) {
+ if (strcmp(descriptor, dex_file.StringByTypeIdx(dex::TypeIndex(type_index))) == 0) {
result = annotation_item;
break;
}
@@ -246,7 +246,7 @@
StackHandleScope<2> hs(self);
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
Handle<mirror::Class> annotation_class(hs.NewHandle(
- class_linker->ResolveType(klass->GetDexFile(), type_index, klass.Get())));
+ class_linker->ResolveType(klass->GetDexFile(), dex::TypeIndex(type_index), klass.Get())));
if (annotation_class.Get() == nullptr) {
LOG(INFO) << "Unable to resolve " << klass->PrettyClass() << " annotation class " << type_index;
DCHECK(Thread::Current()->IsExceptionPending());
@@ -370,13 +370,14 @@
if (result_style == DexFile::kAllRaw) {
annotation_value->value_.SetI(index);
} else {
+ dex::TypeIndex type_index(index);
element_object = Runtime::Current()->GetClassLinker()->ResolveType(
- klass->GetDexFile(), index, klass.Get());
+ klass->GetDexFile(), type_index, klass.Get());
set_object = true;
if (element_object == nullptr) {
CHECK(self->IsExceptionPending());
if (result_style == DexFile::kAllObjects) {
- const char* msg = dex_file.StringByTypeIdx(index);
+ const char* msg = dex_file.StringByTypeIdx(type_index);
self->ThrowNewWrappedException("Ljava/lang/TypeNotPresentException;", msg);
element_object = self->GetException();
self->ClearException();
@@ -665,7 +666,7 @@
const uint8_t* annotation = annotation_item->annotation_;
uint32_t type_index = DecodeUnsignedLeb128(&annotation);
mirror::Class* resolved_class = Runtime::Current()->GetClassLinker()->ResolveType(
- klass->GetDexFile(), type_index, klass.Get());
+ klass->GetDexFile(), dex::TypeIndex(type_index), klass.Get());
if (resolved_class == nullptr) {
std::string temp;
LOG(WARNING) << StringPrintf("Unable to resolve %s annotation class %d",
@@ -1345,7 +1346,9 @@
break;
}
case kType: {
- mirror::Class* resolved = linker_->ResolveType(dex_file_, jval_.i, *dex_cache_,
+ mirror::Class* resolved = linker_->ResolveType(dex_file_,
+ dex::TypeIndex(jval_.i),
+ *dex_cache_,
*class_loader_);
field->SetObject<kTransactionActive>(field->GetDeclaringClass(), resolved);
break;
diff --git a/runtime/dex_file_test.cc b/runtime/dex_file_test.cc
index 8e1501f..f94d07b 100644
--- a/runtime/dex_file_test.cc
+++ b/runtime/dex_file_test.cc
@@ -415,14 +415,14 @@
TEST_F(DexFileTest, FindTypeId) {
for (size_t i = 0; i < java_lang_dex_file_->NumTypeIds(); i++) {
- const char* type_str = java_lang_dex_file_->StringByTypeIdx(i);
+ const char* type_str = java_lang_dex_file_->StringByTypeIdx(dex::TypeIndex(i));
const DexFile::StringId* type_str_id = java_lang_dex_file_->FindStringId(type_str);
ASSERT_TRUE(type_str_id != nullptr);
uint32_t type_str_idx = java_lang_dex_file_->GetIndexForStringId(*type_str_id);
const DexFile::TypeId* type_id = java_lang_dex_file_->FindTypeId(type_str_idx);
ASSERT_EQ(type_id, java_lang_dex_file_->FindTypeId(type_str));
ASSERT_TRUE(type_id != nullptr);
- EXPECT_EQ(java_lang_dex_file_->GetIndexForTypeId(*type_id), i);
+ EXPECT_EQ(java_lang_dex_file_->GetIndexForTypeId(*type_id).index_, i);
}
}
@@ -430,7 +430,7 @@
for (size_t i = 0; i < java_lang_dex_file_->NumProtoIds(); i++) {
const DexFile::ProtoId& to_find = java_lang_dex_file_->GetProtoId(i);
const DexFile::TypeList* to_find_tl = java_lang_dex_file_->GetProtoParameters(to_find);
- std::vector<uint16_t> to_find_types;
+ std::vector<dex::TypeIndex> to_find_types;
if (to_find_tl != nullptr) {
for (size_t j = 0; j < to_find_tl->Size(); j++) {
to_find_types.push_back(to_find_tl->GetTypeItem(j).type_idx_);
diff --git a/runtime/dex_file_types.h b/runtime/dex_file_types.h
new file mode 100644
index 0000000..c6d95a1
--- /dev/null
+++ b/runtime/dex_file_types.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_RUNTIME_DEX_FILE_TYPES_H_
+#define ART_RUNTIME_DEX_FILE_TYPES_H_
+
+#include <limits>
+#include <ostream>
+
+namespace art {
+namespace dex {
+
+class TypeIndex {
+ public:
+ uint16_t index_;
+
+ TypeIndex() : index_(std::numeric_limits<decltype(index_)>::max()) {}
+ explicit TypeIndex(uint16_t idx) : index_(idx) {}
+
+ bool IsValid() const {
+ return index_ != std::numeric_limits<decltype(index_)>::max();
+ }
+ static TypeIndex Invalid() {
+ return TypeIndex(std::numeric_limits<decltype(index_)>::max());
+ }
+
+ bool operator==(const TypeIndex& other) const {
+ return index_ == other.index_;
+ }
+ bool operator!=(const TypeIndex& other) const {
+ return index_ != other.index_;
+ }
+ bool operator<(const TypeIndex& other) const {
+ return index_ < other.index_;
+ }
+ bool operator<=(const TypeIndex& other) const {
+ return index_ <= other.index_;
+ }
+ bool operator>(const TypeIndex& other) const {
+ return index_ > other.index_;
+ }
+ bool operator>=(const TypeIndex& other) const {
+ return index_ >= other.index_;
+ }
+};
+std::ostream& operator<<(std::ostream& os, const TypeIndex& index);
+
+} // namespace dex
+} // namespace art
+
+namespace std {
+
+template<> struct hash<art::dex::TypeIndex> {
+ size_t operator()(const art::dex::TypeIndex& index) const {
+ return hash<uint16_t>()(index.index_);
+ }
+};
+
+} // namespace std
+
+#endif // ART_RUNTIME_DEX_FILE_TYPES_H_
diff --git a/runtime/dex_file_verifier.cc b/runtime/dex_file_verifier.cc
index be25803..ed50711 100644
--- a/runtime/dex_file_verifier.cc
+++ b/runtime/dex_file_verifier.cc
@@ -19,6 +19,7 @@
#include <inttypes.h>
#include <zlib.h>
+#include <limits>
#include <memory>
#include "base/stringprintf.h"
@@ -31,6 +32,16 @@
namespace art {
+static constexpr uint32_t kTypeIdLimit = std::numeric_limits<uint16_t>::max();
+
+static bool IsValidOrNoTypeId(uint16_t low, uint16_t high) {
+ return (high == 0) || ((high == 0xffffU) && (low == 0xffffU));
+}
+
+static bool IsValidTypeId(uint16_t low ATTRIBUTE_UNUSED, uint16_t high) {
+ return (high == 0);
+}
+
static uint32_t MapTypeToBitMask(uint32_t map_type) {
switch (map_type) {
case DexFile::kDexTypeHeaderItem: return 1 << 0;
@@ -76,8 +87,9 @@
return dex_file_->StringDataByIdx(idx);
}
-const char* DexFileVerifier::CheckLoadStringByTypeIdx(uint32_t type_idx, const char* error_string) {
- if (UNLIKELY(!CheckIndex(type_idx, dex_file_->NumTypeIds(), error_string))) {
+const char* DexFileVerifier::CheckLoadStringByTypeIdx(dex::TypeIndex type_idx,
+ const char* error_string) {
+ if (UNLIKELY(!CheckIndex(type_idx.index_, dex_file_->NumTypeIds(), error_string))) {
return nullptr;
}
const DexFile::TypeId& type_id = dex_file_->GetTypeId(type_idx);
@@ -525,7 +537,7 @@
bool DexFileVerifier::CheckClassDataItemField(uint32_t idx,
uint32_t access_flags,
uint32_t class_access_flags,
- uint16_t class_type_index,
+ dex::TypeIndex class_type_index,
bool expect_static) {
// Check for overflow.
if (!CheckIndex(idx, header_->field_ids_size_, "class_data_item field_idx")) {
@@ -533,13 +545,13 @@
}
// Check that it's the right class.
- uint16_t my_class_index =
+ dex::TypeIndex my_class_index =
(reinterpret_cast<const DexFile::FieldId*>(begin_ + header_->field_ids_off_) + idx)->
class_idx_;
if (class_type_index != my_class_index) {
ErrorStringPrintf("Field's class index unexpected, %" PRIu16 "vs %" PRIu16,
- my_class_index,
- class_type_index);
+ my_class_index.index_,
+ class_type_index.index_);
return false;
}
@@ -563,7 +575,7 @@
bool DexFileVerifier::CheckClassDataItemMethod(uint32_t idx,
uint32_t access_flags,
uint32_t class_access_flags,
- uint16_t class_type_index,
+ dex::TypeIndex class_type_index,
uint32_t code_offset,
std::unordered_set<uint32_t>* direct_method_indexes,
bool expect_direct) {
@@ -574,13 +586,13 @@
}
// Check that it's the right class.
- uint16_t my_class_index =
+ dex::TypeIndex my_class_index =
(reinterpret_cast<const DexFile::MethodId*>(begin_ + header_->method_ids_off_) + idx)->
class_idx_;
if (class_type_index != my_class_index) {
- ErrorStringPrintf("Method's class index unexpected, %" PRIu16 "vs %" PRIu16,
- my_class_index,
- class_type_index);
+ ErrorStringPrintf("Method's class index unexpected, %" PRIu16 " vs %" PRIu16,
+ my_class_index.index_,
+ class_type_index.index_);
return false;
}
@@ -789,7 +801,7 @@
bool DexFileVerifier::FindClassFlags(uint32_t index,
bool is_field,
- uint16_t* class_type_index,
+ dex::TypeIndex* class_type_index,
uint32_t* class_access_flags) {
DCHECK(class_type_index != nullptr);
DCHECK(class_access_flags != nullptr);
@@ -811,7 +823,7 @@
}
// Check if that is valid.
- if (*class_type_index >= header_->type_ids_size_) {
+ if (class_type_index->index_ >= header_->type_ids_size_) {
return false;
}
@@ -836,7 +848,7 @@
uint32_t curr_index,
uint32_t prev_index,
bool* have_class,
- uint16_t* class_type_index,
+ dex::TypeIndex* class_type_index,
uint32_t* class_access_flags) {
if (curr_index < prev_index) {
ErrorStringPrintf("out-of-order %s indexes %" PRIu32 " and %" PRIu32,
@@ -862,7 +874,7 @@
template <bool kStatic>
bool DexFileVerifier::CheckIntraClassDataItemFields(ClassDataItemIterator* it,
bool* have_class,
- uint16_t* class_type_index,
+ dex::TypeIndex* class_type_index,
uint32_t* class_access_flags) {
DCHECK(it != nullptr);
// These calls use the raw access flags to check whether the whole dex field is valid.
@@ -897,7 +909,7 @@
ClassDataItemIterator* it,
std::unordered_set<uint32_t>* direct_method_indexes,
bool* have_class,
- uint16_t* class_type_index,
+ dex::TypeIndex* class_type_index,
uint32_t* class_access_flags) {
uint32_t prev_index = 0;
for (; kDirect ? it->HasNextDirectMethod() : it->HasNextVirtualMethod(); it->Next()) {
@@ -935,7 +947,7 @@
// So we need to explicitly search with the first item we find (either field or method), and then,
// as the lookup is expensive, cache the result.
bool have_class = false;
- uint16_t class_type_index;
+ dex::TypeIndex class_type_index;
uint32_t class_access_flags;
// Check fields.
@@ -1682,26 +1694,27 @@
return true;
}
-uint16_t DexFileVerifier::FindFirstClassDataDefiner(const uint8_t* ptr, bool* success) {
+dex::TypeIndex DexFileVerifier::FindFirstClassDataDefiner(const uint8_t* ptr, bool* success) {
ClassDataItemIterator it(*dex_file_, ptr);
*success = true;
if (it.HasNextStaticField() || it.HasNextInstanceField()) {
LOAD_FIELD(field, it.GetMemberIndex(), "first_class_data_definer field_id",
- *success = false; return DexFile::kDexNoIndex16)
+ *success = false; return dex::TypeIndex(DexFile::kDexNoIndex16))
return field->class_idx_;
}
if (it.HasNextDirectMethod() || it.HasNextVirtualMethod()) {
LOAD_METHOD(method, it.GetMemberIndex(), "first_class_data_definer method_id",
- *success = false; return DexFile::kDexNoIndex16)
+ *success = false; return dex::TypeIndex(DexFile::kDexNoIndex16))
return method->class_idx_;
}
- return DexFile::kDexNoIndex16;
+ return dex::TypeIndex(DexFile::kDexNoIndex16);
}
-uint16_t DexFileVerifier::FindFirstAnnotationsDirectoryDefiner(const uint8_t* ptr, bool* success) {
+dex::TypeIndex DexFileVerifier::FindFirstAnnotationsDirectoryDefiner(const uint8_t* ptr,
+ bool* success) {
const DexFile::AnnotationsDirectoryItem* item =
reinterpret_cast<const DexFile::AnnotationsDirectoryItem*>(ptr);
*success = true;
@@ -1709,25 +1722,25 @@
if (item->fields_size_ != 0) {
DexFile::FieldAnnotationsItem* field_items = (DexFile::FieldAnnotationsItem*) (item + 1);
LOAD_FIELD(field, field_items[0].field_idx_, "first_annotations_dir_definer field_id",
- *success = false; return DexFile::kDexNoIndex16)
+ *success = false; return dex::TypeIndex(DexFile::kDexNoIndex16))
return field->class_idx_;
}
if (item->methods_size_ != 0) {
DexFile::MethodAnnotationsItem* method_items = (DexFile::MethodAnnotationsItem*) (item + 1);
LOAD_METHOD(method, method_items[0].method_idx_, "first_annotations_dir_definer method id",
- *success = false; return DexFile::kDexNoIndex16)
+ *success = false; return dex::TypeIndex(DexFile::kDexNoIndex16))
return method->class_idx_;
}
if (item->parameters_size_ != 0) {
DexFile::ParameterAnnotationsItem* parameter_items = (DexFile::ParameterAnnotationsItem*) (item + 1);
LOAD_METHOD(method, parameter_items[0].method_idx_, "first_annotations_dir_definer method id",
- *success = false; return DexFile::kDexNoIndex16)
+ *success = false; return dex::TypeIndex(DexFile::kDexNoIndex16))
return method->class_idx_;
}
- return DexFile::kDexNoIndex16;
+ return dex::TypeIndex(DexFile::kDexNoIndex16);
}
bool DexFileVerifier::CheckInterStringIdItem() {
@@ -1788,6 +1801,12 @@
return false;
}
+ // Check that return type is representable as a uint16_t;
+ if (UNLIKELY(!IsValidOrNoTypeId(item->return_type_idx_.index_, item->pad_))) {
+ ErrorStringPrintf("proto with return type idx outside uint16_t range '%x:%x'",
+ item->pad_, item->return_type_idx_.index_);
+ return false;
+ }
// Check the return type and advance the shorty.
LOAD_STRING_BY_TYPE(return_type, item->return_type_idx_, "inter_proto_id_item return_type_idx")
if (!CheckShortyDescriptorMatch(*shorty, return_type, true)) {
@@ -1797,7 +1816,8 @@
DexFileParameterIterator it(*dex_file_, *item);
while (it.HasNext() && *shorty != '\0') {
- if (!CheckIndex(it.GetTypeIdx(), dex_file_->NumTypeIds(),
+ if (!CheckIndex(it.GetTypeIdx().index_,
+ dex_file_->NumTypeIds(),
"inter_proto_id_item shorty type_idx")) {
return false;
}
@@ -1824,10 +1844,10 @@
DexFileParameterIterator prev_it(*dex_file_, *prev);
while (curr_it.HasNext() && prev_it.HasNext()) {
- uint16_t prev_idx = prev_it.GetTypeIdx();
- uint16_t curr_idx = curr_it.GetTypeIdx();
- DCHECK_NE(prev_idx, DexFile::kDexNoIndex16);
- DCHECK_NE(curr_idx, DexFile::kDexNoIndex16);
+ dex::TypeIndex prev_idx = prev_it.GetTypeIdx();
+ dex::TypeIndex curr_idx = curr_it.GetTypeIdx();
+ DCHECK_NE(prev_idx, dex::TypeIndex(DexFile::kDexNoIndex16));
+ DCHECK_NE(curr_idx, dex::TypeIndex(DexFile::kDexNoIndex16));
if (prev_idx < curr_idx) {
break;
@@ -1949,9 +1969,21 @@
bool DexFileVerifier::CheckInterClassDefItem() {
const DexFile::ClassDef* item = reinterpret_cast<const DexFile::ClassDef*>(ptr_);
+ // Check that class_idx_ is representable as a uint16_t;
+ if (UNLIKELY(!IsValidTypeId(item->class_idx_.index_, item->pad1_))) {
+ ErrorStringPrintf("class with type idx outside uint16_t range '%x:%x'", item->pad1_,
+ item->class_idx_.index_);
+ return false;
+ }
+ // Check that superclass_idx_ is representable as a uint16_t;
+ if (UNLIKELY(!IsValidOrNoTypeId(item->superclass_idx_.index_, item->pad2_))) {
+ ErrorStringPrintf("class with superclass type idx outside uint16_t range '%x:%x'", item->pad2_,
+ item->superclass_idx_.index_);
+ return false;
+ }
// Check for duplicate class def.
if (defined_classes_.find(item->class_idx_) != defined_classes_.end()) {
- ErrorStringPrintf("Redefinition of class with type idx: '%d'", item->class_idx_);
+ ErrorStringPrintf("Redefinition of class with type idx: '%d'", item->class_idx_.index_);
return false;
}
defined_classes_.insert(item->class_idx_);
@@ -1985,12 +2017,13 @@
return false;
}
- if (item->superclass_idx_ != DexFile::kDexNoIndex16) {
+ if (item->superclass_idx_.IsValid()) {
if (header_->GetVersion() >= DexFile::kClassDefinitionOrderEnforcedVersion) {
// Check that a class does not inherit from itself directly (by having
// the same type idx as its super class).
if (UNLIKELY(item->superclass_idx_ == item->class_idx_)) {
- ErrorStringPrintf("Class with same type idx as its superclass: '%d'", item->class_idx_);
+ ErrorStringPrintf("Class with same type idx as its superclass: '%d'",
+ item->class_idx_.index_);
return false;
}
@@ -2004,8 +2037,8 @@
ErrorStringPrintf("Invalid class definition ordering:"
" class with type idx: '%d' defined before"
" superclass with type idx: '%d'",
- item->class_idx_,
- item->superclass_idx_);
+ item->class_idx_.index_,
+ item->superclass_idx_.index_);
return false;
}
}
@@ -2029,7 +2062,7 @@
// same type idx as one of its immediate implemented interfaces).
if (UNLIKELY(interfaces->GetTypeItem(i).type_idx_ == item->class_idx_)) {
ErrorStringPrintf("Class with same type idx as implemented interface: '%d'",
- item->class_idx_);
+ item->class_idx_.index_);
return false;
}
@@ -2044,8 +2077,8 @@
ErrorStringPrintf("Invalid class definition ordering:"
" class with type idx: '%d' defined before"
" implemented interface with type idx: '%d'",
- item->class_idx_,
- interfaces->GetTypeItem(i).type_idx_);
+ item->class_idx_.index_,
+ interfaces->GetTypeItem(i).type_idx_.index_);
return false;
}
}
@@ -2065,9 +2098,9 @@
* practice the number of interfaces implemented by any given class is low.
*/
for (uint32_t i = 1; i < size; i++) {
- uint32_t idx1 = interfaces->GetTypeItem(i).type_idx_;
+ dex::TypeIndex idx1 = interfaces->GetTypeItem(i).type_idx_;
for (uint32_t j =0; j < i; j++) {
- uint32_t idx2 = interfaces->GetTypeItem(j).type_idx_;
+ dex::TypeIndex idx2 = interfaces->GetTypeItem(j).type_idx_;
if (UNLIKELY(idx1 == idx2)) {
ErrorStringPrintf("Duplicate interface: '%s'", dex_file_->StringByTypeIdx(idx1));
return false;
@@ -2080,11 +2113,12 @@
if (item->class_data_off_ != 0) {
const uint8_t* data = begin_ + item->class_data_off_;
bool success;
- uint16_t data_definer = FindFirstClassDataDefiner(data, &success);
+ dex::TypeIndex data_definer = FindFirstClassDataDefiner(data, &success);
if (!success) {
return false;
}
- if (UNLIKELY((data_definer != item->class_idx_) && (data_definer != DexFile::kDexNoIndex16))) {
+ if (UNLIKELY((data_definer != item->class_idx_) &&
+ (data_definer != dex::TypeIndex(DexFile::kDexNoIndex16)))) {
ErrorStringPrintf("Invalid class_data_item");
return false;
}
@@ -2099,12 +2133,12 @@
}
const uint8_t* data = begin_ + item->annotations_off_;
bool success;
- uint16_t annotations_definer = FindFirstAnnotationsDirectoryDefiner(data, &success);
+ dex::TypeIndex annotations_definer = FindFirstAnnotationsDirectoryDefiner(data, &success);
if (!success) {
return false;
}
if (UNLIKELY((annotations_definer != item->class_idx_) &&
- (annotations_definer != DexFile::kDexNoIndex16))) {
+ (annotations_definer != dex::TypeIndex(DexFile::kDexNoIndex16)))) {
ErrorStringPrintf("Invalid annotations_directory_item");
return false;
}
@@ -2165,7 +2199,7 @@
bool DexFileVerifier::CheckInterClassDataItem() {
ClassDataItemIterator it(*dex_file_, ptr_);
bool success;
- uint16_t defining_class = FindFirstClassDataDefiner(ptr_, &success);
+ dex::TypeIndex defining_class = FindFirstClassDataDefiner(ptr_, &success);
if (!success) {
return false;
}
@@ -2197,7 +2231,7 @@
const DexFile::AnnotationsDirectoryItem* item =
reinterpret_cast<const DexFile::AnnotationsDirectoryItem*>(ptr_);
bool success;
- uint16_t defining_class = FindFirstAnnotationsDirectoryDefiner(ptr_, &success);
+ dex::TypeIndex defining_class = FindFirstAnnotationsDirectoryDefiner(ptr_, &success);
if (!success) {
return false;
}
@@ -2315,6 +2349,14 @@
break;
}
case DexFile::kDexTypeClassDefItem: {
+ // There shouldn't be more class definitions than type ids allow.
+ // This check should be redundant, since there are checks that the
+ // class_idx_ is within range and that there is only one definition
+ // for a given type id.
+ if (i > kTypeIdLimit) {
+ ErrorStringPrintf("Too many class definition items");
+ return false;
+ }
if (!CheckInterClassDefItem()) {
return false;
}
@@ -2333,6 +2375,14 @@
break;
}
case DexFile::kDexTypeClassDataItem: {
+ // There shouldn't be more class data than type ids allow.
+ // This check should be redundant, since there are checks that the
+ // class_idx_ is within range and that there is only one definition
+ // for a given type id.
+ if (i > kTypeIdLimit) {
+ ErrorStringPrintf("Too many class data items");
+ return false;
+ }
if (!CheckInterClassDataItem()) {
return false;
}
@@ -2471,15 +2521,15 @@
static std::string GetClassOrError(const uint8_t* const begin,
const DexFile::Header* const header,
- uint32_t class_idx) {
+ dex::TypeIndex class_idx) {
// The `class_idx` is either `FieldId::class_idx_` or `MethodId::class_idx_` and
// it has already been checked in `DexFileVerifier::CheckClassDataItemField()`
// or `DexFileVerifier::CheckClassDataItemMethod()`, respectively, to match
// a valid defining class.
- CHECK_LT(class_idx, header->type_ids_size_);
+ CHECK_LT(class_idx.index_, header->type_ids_size_);
const DexFile::TypeId* type_id =
- reinterpret_cast<const DexFile::TypeId*>(begin + header->type_ids_off_) + class_idx;
+ reinterpret_cast<const DexFile::TypeId*>(begin + header->type_ids_off_) + class_idx.index_;
// Assume that the data is OK at this point. Type id offsets have been checked at this point.
diff --git a/runtime/dex_file_verifier.h b/runtime/dex_file_verifier.h
index 133e432..19a89de 100644
--- a/runtime/dex_file_verifier.h
+++ b/runtime/dex_file_verifier.h
@@ -20,6 +20,7 @@
#include <unordered_set>
#include "dex_file.h"
+#include "dex_file_types.h"
#include "safe_map.h"
namespace art {
@@ -76,12 +77,12 @@
bool CheckClassDataItemField(uint32_t idx,
uint32_t access_flags,
uint32_t class_access_flags,
- uint16_t class_type_index,
+ dex::TypeIndex class_type_index,
bool expect_static);
bool CheckClassDataItemMethod(uint32_t idx,
uint32_t access_flags,
uint32_t class_access_flags,
- uint16_t class_type_index,
+ dex::TypeIndex class_type_index,
uint32_t code_offset,
std::unordered_set<uint32_t>* direct_method_indexes,
bool expect_direct);
@@ -90,7 +91,7 @@
uint32_t curr_index,
uint32_t prev_index,
bool* have_class,
- uint16_t* class_type_index,
+ dex::TypeIndex* class_type_index,
uint32_t* class_access_flags);
bool CheckPadding(size_t offset, uint32_t aligned_offset);
@@ -104,7 +105,7 @@
template <bool kStatic>
bool CheckIntraClassDataItemFields(ClassDataItemIterator* it,
bool* have_class,
- uint16_t* class_type_index,
+ dex::TypeIndex* class_type_index,
uint32_t* class_access_flags);
// Check all methods of the given type from the given iterator. Load the class data from the first
// method, if necessary (and return it), or use the given values.
@@ -112,7 +113,7 @@
bool CheckIntraClassDataItemMethods(ClassDataItemIterator* it,
std::unordered_set<uint32_t>* direct_method_indexes,
bool* have_class,
- uint16_t* class_type_index,
+ dex::TypeIndex* class_type_index,
uint32_t* class_access_flags);
bool CheckIntraCodeItem();
@@ -130,8 +131,8 @@
// Note: as sometimes kDexNoIndex16, being 0xFFFF, is a valid return value, we need an
// additional out parameter to signal any errors loading an index.
- uint16_t FindFirstClassDataDefiner(const uint8_t* ptr, bool* success);
- uint16_t FindFirstAnnotationsDirectoryDefiner(const uint8_t* ptr, bool* success);
+ dex::TypeIndex FindFirstClassDataDefiner(const uint8_t* ptr, bool* success);
+ dex::TypeIndex FindFirstAnnotationsDirectoryDefiner(const uint8_t* ptr, bool* success);
bool CheckInterStringIdItem();
bool CheckInterTypeIdItem();
@@ -150,7 +151,7 @@
// Load a string by (type) index. Checks whether the index is in bounds, printing the error if
// not. If there is an error, null is returned.
const char* CheckLoadStringByIdx(uint32_t idx, const char* error_fmt);
- const char* CheckLoadStringByTypeIdx(uint32_t type_idx, const char* error_fmt);
+ const char* CheckLoadStringByTypeIdx(dex::TypeIndex type_idx, const char* error_fmt);
// Load a field/method Id by index. Checks whether the index is in bounds, printing the error if
// not. If there is an error, null is returned.
@@ -168,7 +169,7 @@
// linear search. The output values should thus be cached by the caller.
bool FindClassFlags(uint32_t index,
bool is_field,
- uint16_t* class_type_index,
+ dex::TypeIndex* class_type_index,
uint32_t* class_access_flags);
// Check validity of the given access flags, interpreted for a field in the context of a class
diff --git a/runtime/dex_file_verifier_test.cc b/runtime/dex_file_verifier_test.cc
index 3801c22..0e0929f 100644
--- a/runtime/dex_file_verifier_test.cc
+++ b/runtime/dex_file_verifier_test.cc
@@ -26,6 +26,7 @@
#include "base/macros.h"
#include "common_runtime_test.h"
#include "dex_file-inl.h"
+#include "dex_file_types.h"
#include "leb128.h"
#include "scoped_thread_state_change-inl.h"
#include "thread-inl.h"
@@ -155,7 +156,7 @@
"method_id_class_idx",
[](DexFile* dex_file) {
DexFile::MethodId* method_id = const_cast<DexFile::MethodId*>(&dex_file->GetMethodId(0));
- method_id->class_idx_ = 0xFF;
+ method_id->class_idx_ = dex::TypeIndex(0xFF);
},
"could not find declaring class for direct method index 0");
diff --git a/runtime/dex_instruction.cc b/runtime/dex_instruction.cc
index c766b54..751bd51 100644
--- a/runtime/dex_instruction.cc
+++ b/runtime/dex_instruction.cc
@@ -208,9 +208,9 @@
case CONST_CLASS:
case NEW_INSTANCE:
if (file != nullptr) {
- uint32_t type_idx = VRegB_21c();
- os << opcode << " v" << static_cast<int>(VRegA_21c()) << ", " << file->PrettyType(type_idx)
- << " // type@" << type_idx;
+ dex::TypeIndex type_idx(VRegB_21c());
+ os << opcode << " v" << static_cast<int>(VRegA_21c()) << ", "
+ << file->PrettyType(type_idx) << " // type@" << type_idx;
break;
}
FALLTHROUGH_INTENDED;
@@ -302,17 +302,19 @@
FALLTHROUGH_INTENDED;
case INSTANCE_OF:
if (file != nullptr) {
- uint32_t type_idx = VRegC_22c();
- os << opcode << " v" << static_cast<int>(VRegA_22c()) << ", v" << static_cast<int>(VRegB_22c()) << ", "
- << file->PrettyType(type_idx) << " // type@" << type_idx;
+ dex::TypeIndex type_idx(VRegC_22c());
+ os << opcode << " v" << static_cast<int>(VRegA_22c()) << ", v"
+ << static_cast<int>(VRegB_22c()) << ", " << file->PrettyType(type_idx)
+ << " // type@" << type_idx.index_;
break;
}
FALLTHROUGH_INTENDED;
case NEW_ARRAY:
if (file != nullptr) {
- uint32_t type_idx = VRegC_22c();
- os << opcode << " v" << static_cast<int>(VRegA_22c()) << ", v" << static_cast<int>(VRegB_22c()) << ", "
- << file->PrettyType(type_idx) << " // type@" << type_idx;
+ dex::TypeIndex type_idx(VRegC_22c());
+ os << opcode << " v" << static_cast<int>(VRegA_22c()) << ", v"
+ << static_cast<int>(VRegB_22c()) << ", " << file->PrettyType(type_idx)
+ << " // type@" << type_idx.index_;
break;
}
FALLTHROUGH_INTENDED;
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/entrypoints/entrypoint_utils-inl.h b/runtime/entrypoints/entrypoint_utils-inl.h
index ed60f59..ac52f4e 100644
--- a/runtime/entrypoints/entrypoint_utils-inl.h
+++ b/runtime/entrypoints/entrypoint_utils-inl.h
@@ -129,7 +129,7 @@
template <const bool kAccessCheck>
ALWAYS_INLINE
-inline mirror::Class* CheckObjectAlloc(uint32_t type_idx,
+inline mirror::Class* CheckObjectAlloc(dex::TypeIndex type_idx,
ArtMethod* method,
Thread* self,
bool* slow_path) {
@@ -219,7 +219,7 @@
// check.
template <bool kAccessCheck, bool kInstrumented>
ALWAYS_INLINE
-inline mirror::Object* AllocObjectFromCode(uint32_t type_idx,
+inline mirror::Object* AllocObjectFromCode(dex::TypeIndex type_idx,
ArtMethod* method,
Thread* self,
gc::AllocatorType allocator_type) {
@@ -275,7 +275,7 @@
template <bool kAccessCheck>
ALWAYS_INLINE
-inline mirror::Class* CheckArrayAlloc(uint32_t type_idx,
+inline mirror::Class* CheckArrayAlloc(dex::TypeIndex type_idx,
int32_t component_count,
ArtMethod* method,
bool* slow_path) {
@@ -313,7 +313,7 @@
// check.
template <bool kAccessCheck, bool kInstrumented>
ALWAYS_INLINE
-inline mirror::Array* AllocArrayFromCode(uint32_t type_idx,
+inline mirror::Array* AllocArrayFromCode(dex::TypeIndex type_idx,
int32_t component_count,
ArtMethod* method,
Thread* self,
@@ -562,7 +562,7 @@
StackHandleScope<2> hs2(self);
HandleWrapperObjPtr<mirror::Object> h_this(hs2.NewHandleWrapper(this_object));
Handle<mirror::Class> h_referring_class(hs2.NewHandle(referrer->GetDeclaringClass()));
- const uint16_t method_type_idx =
+ const dex::TypeIndex method_type_idx =
h_referring_class->GetDexFile().GetMethodId(method_idx).class_idx_;
mirror::Class* method_reference_class = class_linker->ResolveType(method_type_idx, referrer);
if (UNLIKELY(method_reference_class == nullptr)) {
@@ -758,7 +758,8 @@
return resolved_method;
} else if (type == kSuper) {
// TODO This lookup is rather slow.
- uint16_t method_type_idx = referring_class->GetDexFile().GetMethodId(method_idx).class_idx_;
+ dex::TypeIndex method_type_idx =
+ referring_class->GetDexFile().GetMethodId(method_idx).class_idx_;
mirror::Class* method_reference_class =
referring_class->GetDexCache()->GetResolvedType(method_type_idx);
if (method_reference_class == nullptr) {
@@ -788,8 +789,11 @@
}
}
-inline mirror::Class* ResolveVerifyAndClinit(uint32_t type_idx, ArtMethod* referrer, Thread* self,
- bool can_run_clinit, bool verify_access) {
+inline mirror::Class* ResolveVerifyAndClinit(dex::TypeIndex type_idx,
+ ArtMethod* referrer,
+ Thread* self,
+ bool can_run_clinit,
+ bool verify_access) {
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
mirror::Class* klass = class_linker->ResolveType(type_idx, referrer);
if (UNLIKELY(klass == nullptr)) {
diff --git a/runtime/entrypoints/entrypoint_utils.cc b/runtime/entrypoints/entrypoint_utils.cc
index 1ccb4b0..5390165 100644
--- a/runtime/entrypoints/entrypoint_utils.cc
+++ b/runtime/entrypoints/entrypoint_utils.cc
@@ -38,7 +38,7 @@
namespace art {
-static inline mirror::Class* CheckFilledNewArrayAlloc(uint32_t type_idx,
+static inline mirror::Class* CheckFilledNewArrayAlloc(dex::TypeIndex type_idx,
int32_t component_count,
ArtMethod* referrer,
Thread* self,
@@ -82,10 +82,12 @@
}
// Helper function to allocate array for FILLED_NEW_ARRAY.
-mirror::Array* CheckAndAllocArrayFromCode(uint32_t type_idx, int32_t component_count,
- ArtMethod* referrer, Thread* self,
+mirror::Array* CheckAndAllocArrayFromCode(dex::TypeIndex type_idx,
+ int32_t component_count,
+ ArtMethod* referrer,
+ Thread* self,
bool access_check,
- gc::AllocatorType /* allocator_type */) {
+ gc::AllocatorType allocator_type ATTRIBUTE_UNUSED) {
mirror::Class* klass = CheckFilledNewArrayAlloc(type_idx, component_count, referrer, self,
access_check);
if (UNLIKELY(klass == nullptr)) {
@@ -101,12 +103,13 @@
}
// Helper function to allocate array for FILLED_NEW_ARRAY.
-mirror::Array* CheckAndAllocArrayFromCodeInstrumented(uint32_t type_idx,
- int32_t component_count,
- ArtMethod* referrer,
- Thread* self,
- bool access_check,
- gc::AllocatorType /* allocator_type */) {
+mirror::Array* CheckAndAllocArrayFromCodeInstrumented(
+ dex::TypeIndex type_idx,
+ int32_t component_count,
+ ArtMethod* referrer,
+ Thread* self,
+ bool access_check,
+ gc::AllocatorType allocator_type ATTRIBUTE_UNUSED) {
mirror::Class* klass = CheckFilledNewArrayAlloc(type_idx, component_count, referrer, self,
access_check);
if (UNLIKELY(klass == nullptr)) {
diff --git a/runtime/entrypoints/entrypoint_utils.h b/runtime/entrypoints/entrypoint_utils.h
index bcddfb0..d87dc67 100644
--- a/runtime/entrypoints/entrypoint_utils.h
+++ b/runtime/entrypoints/entrypoint_utils.h
@@ -23,6 +23,7 @@
#include "base/macros.h"
#include "base/mutex.h"
#include "dex_instruction.h"
+#include "dex_file_types.h"
#include "gc/allocator_type.h"
#include "handle.h"
#include "invoke_type.h"
@@ -45,7 +46,7 @@
class Thread;
template <const bool kAccessCheck>
-ALWAYS_INLINE inline mirror::Class* CheckObjectAlloc(uint32_t type_idx,
+ALWAYS_INLINE inline mirror::Class* CheckObjectAlloc(dex::TypeIndex type_idx,
ArtMethod* method,
Thread* self,
bool* slow_path)
@@ -63,7 +64,7 @@
// When verification/compiler hasn't been able to verify access, optionally perform an access
// check.
template <bool kAccessCheck, bool kInstrumented>
-ALWAYS_INLINE inline mirror::Object* AllocObjectFromCode(uint32_t type_idx,
+ALWAYS_INLINE inline mirror::Object* AllocObjectFromCode(dex::TypeIndex type_idx,
ArtMethod* method,
Thread* self,
gc::AllocatorType allocator_type)
@@ -89,7 +90,7 @@
template <bool kAccessCheck>
-ALWAYS_INLINE inline mirror::Class* CheckArrayAlloc(uint32_t type_idx,
+ALWAYS_INLINE inline mirror::Class* CheckArrayAlloc(dex::TypeIndex type_idx,
int32_t component_count,
ArtMethod* method,
bool* slow_path)
@@ -101,7 +102,7 @@
// When verification/compiler hasn't been able to verify access, optionally perform an access
// check.
template <bool kAccessCheck, bool kInstrumented>
-ALWAYS_INLINE inline mirror::Array* AllocArrayFromCode(uint32_t type_idx,
+ALWAYS_INLINE inline mirror::Array* AllocArrayFromCode(dex::TypeIndex type_idx,
int32_t component_count,
ArtMethod* method,
Thread* self,
@@ -118,19 +119,21 @@
REQUIRES_SHARED(Locks::mutator_lock_)
REQUIRES(!Roles::uninterruptible_);
-extern mirror::Array* CheckAndAllocArrayFromCode(uint32_t type_idx, int32_t component_count,
- ArtMethod* method, Thread* self,
- bool access_check,
- gc::AllocatorType allocator_type)
+mirror::Array* CheckAndAllocArrayFromCode(dex::TypeIndex type_idx,
+ int32_t component_count,
+ ArtMethod* method,
+ Thread* self,
+ bool access_check,
+ gc::AllocatorType allocator_type)
REQUIRES_SHARED(Locks::mutator_lock_)
REQUIRES(!Roles::uninterruptible_);
-extern mirror::Array* CheckAndAllocArrayFromCodeInstrumented(uint32_t type_idx,
- int32_t component_count,
- ArtMethod* method,
- Thread* self,
- bool access_check,
- gc::AllocatorType allocator_type)
+mirror::Array* CheckAndAllocArrayFromCodeInstrumented(dex::TypeIndex type_idx,
+ int32_t component_count,
+ ArtMethod* method,
+ Thread* self,
+ bool access_check,
+ gc::AllocatorType allocator_type)
REQUIRES_SHARED(Locks::mutator_lock_)
REQUIRES(!Roles::uninterruptible_);
@@ -177,7 +180,7 @@
InvokeType type)
REQUIRES_SHARED(Locks::mutator_lock_);
-inline mirror::Class* ResolveVerifyAndClinit(uint32_t type_idx,
+inline mirror::Class* ResolveVerifyAndClinit(dex::TypeIndex type_idx,
ArtMethod* referrer,
Thread* self,
bool can_run_clinit,
diff --git a/runtime/entrypoints/quick/quick_alloc_entrypoints.cc b/runtime/entrypoints/quick/quick_alloc_entrypoints.cc
index 4a7e819..d2fee9a 100644
--- a/runtime/entrypoints/quick/quick_alloc_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_alloc_entrypoints.cc
@@ -19,6 +19,7 @@
#include "art_method-inl.h"
#include "base/enums.h"
#include "callee_save_frame.h"
+#include "dex_file_types.h"
#include "entrypoints/entrypoint_utils-inl.h"
#include "mirror/class-inl.h"
#include "mirror/object_array-inl.h"
@@ -34,7 +35,8 @@
REQUIRES_SHARED(Locks::mutator_lock_) { \
ScopedQuickEntrypointChecks sqec(self); \
if (kUseTlabFastPath && !(instrumented_bool) && (allocator_type) == gc::kAllocatorTypeTLAB) { \
- mirror::Class* klass = method->GetDexCacheResolvedType<false>(type_idx, kRuntimePointerSize); \
+ mirror::Class* klass = method->GetDexCacheResolvedType<false>(dex::TypeIndex(type_idx), \
+ kRuntimePointerSize); \
if (LIKELY(klass != nullptr && klass->IsInitialized() && !klass->IsFinalizable())) { \
size_t byte_count = klass->GetObjectSize(); \
byte_count = RoundUp(byte_count, gc::space::BumpPointerSpace::kAlignment); \
@@ -51,7 +53,10 @@
} \
} \
} \
- return AllocObjectFromCode<false, instrumented_bool>(type_idx, method, self, allocator_type); \
+ return AllocObjectFromCode<false, instrumented_bool>(dex::TypeIndex(type_idx), \
+ method, \
+ self, \
+ allocator_type); \
} \
extern "C" mirror::Object* artAllocObjectFromCodeResolved##suffix##suffix2( \
mirror::Class* klass, ArtMethod* method ATTRIBUTE_UNUSED, Thread* self) \
@@ -101,13 +106,19 @@
uint32_t type_idx, ArtMethod* method, Thread* self) \
REQUIRES_SHARED(Locks::mutator_lock_) { \
ScopedQuickEntrypointChecks sqec(self); \
- return AllocObjectFromCode<true, instrumented_bool>(type_idx, method, self, allocator_type); \
+ return AllocObjectFromCode<true, instrumented_bool>(dex::TypeIndex(type_idx), \
+ method, \
+ self, \
+ allocator_type); \
} \
extern "C" mirror::Array* artAllocArrayFromCode##suffix##suffix2( \
uint32_t type_idx, int32_t component_count, ArtMethod* method, Thread* self) \
REQUIRES_SHARED(Locks::mutator_lock_) { \
ScopedQuickEntrypointChecks sqec(self); \
- return AllocArrayFromCode<false, instrumented_bool>(type_idx, component_count, method, self, \
+ return AllocArrayFromCode<false, instrumented_bool>(dex::TypeIndex(type_idx), \
+ component_count, \
+ method, \
+ self, \
allocator_type); \
} \
extern "C" mirror::Array* artAllocArrayFromCodeResolved##suffix##suffix2( \
@@ -121,7 +132,10 @@
uint32_t type_idx, int32_t component_count, ArtMethod* method, Thread* self) \
REQUIRES_SHARED(Locks::mutator_lock_) { \
ScopedQuickEntrypointChecks sqec(self); \
- return AllocArrayFromCode<true, instrumented_bool>(type_idx, component_count, method, self, \
+ return AllocArrayFromCode<true, instrumented_bool>(dex::TypeIndex(type_idx), \
+ component_count, \
+ method, \
+ self, \
allocator_type); \
} \
extern "C" mirror::Array* artCheckAndAllocArrayFromCode##suffix##suffix2( \
@@ -129,9 +143,19 @@
REQUIRES_SHARED(Locks::mutator_lock_) { \
ScopedQuickEntrypointChecks sqec(self); \
if (!(instrumented_bool)) { \
- return CheckAndAllocArrayFromCode(type_idx, component_count, method, self, false, allocator_type); \
+ return CheckAndAllocArrayFromCode(dex::TypeIndex(type_idx), \
+ component_count, \
+ method, \
+ self, \
+ false, \
+ allocator_type); \
} else { \
- return CheckAndAllocArrayFromCodeInstrumented(type_idx, component_count, method, self, false, allocator_type); \
+ return CheckAndAllocArrayFromCodeInstrumented(dex::TypeIndex(type_idx), \
+ component_count, \
+ method, \
+ self, \
+ false, \
+ allocator_type); \
} \
} \
extern "C" mirror::Array* artCheckAndAllocArrayFromCodeWithAccessCheck##suffix##suffix2( \
@@ -139,9 +163,19 @@
REQUIRES_SHARED(Locks::mutator_lock_) { \
ScopedQuickEntrypointChecks sqec(self); \
if (!(instrumented_bool)) { \
- return CheckAndAllocArrayFromCode(type_idx, component_count, method, self, true, allocator_type); \
+ return CheckAndAllocArrayFromCode(dex::TypeIndex(type_idx), \
+ component_count, \
+ method, \
+ self, \
+ true, \
+ allocator_type); \
} else { \
- return CheckAndAllocArrayFromCodeInstrumented(type_idx, component_count, method, self, true, allocator_type); \
+ return CheckAndAllocArrayFromCodeInstrumented(dex::TypeIndex(type_idx), \
+ component_count, \
+ method, \
+ self, \
+ true, \
+ allocator_type); \
} \
} \
extern "C" mirror::String* artAllocStringFromBytesFromCode##suffix##suffix2( \
diff --git a/runtime/entrypoints/quick/quick_dexcache_entrypoints.cc b/runtime/entrypoints/quick/quick_dexcache_entrypoints.cc
index d438418..b1259e1 100644
--- a/runtime/entrypoints/quick/quick_dexcache_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_dexcache_entrypoints.cc
@@ -20,6 +20,7 @@
#include "class_linker-inl.h"
#include "class_table-inl.h"
#include "dex_file-inl.h"
+#include "dex_file_types.h"
#include "gc/heap.h"
#include "mirror/class-inl.h"
#include "mirror/class_loader.h"
@@ -37,7 +38,7 @@
// given by inheritance.
ScopedQuickEntrypointChecks sqec(self);
auto* caller = GetCalleeSaveMethodCaller(self, Runtime::kSaveRefsOnly);
- return ResolveVerifyAndClinit(type_idx, caller, self, true, false);
+ return ResolveVerifyAndClinit(dex::TypeIndex(type_idx), caller, self, true, false);
}
extern "C" mirror::Class* artInitializeTypeFromCode(uint32_t type_idx, Thread* self)
@@ -45,7 +46,7 @@
// Called when method->dex_cache_resolved_types_[] misses.
ScopedQuickEntrypointChecks sqec(self);
auto* caller = GetCalleeSaveMethodCaller(self, Runtime::kSaveRefsOnly);
- return ResolveVerifyAndClinit(type_idx, caller, self, false, false);
+ return ResolveVerifyAndClinit(dex::TypeIndex(type_idx), caller, self, false, false);
}
extern "C" mirror::Class* artInitializeTypeAndVerifyAccessFromCode(uint32_t type_idx, Thread* self)
@@ -54,7 +55,7 @@
// unpopulated.
ScopedQuickEntrypointChecks sqec(self);
auto* caller = GetCalleeSaveMethodCaller(self, Runtime::kSaveRefsOnly);
- return ResolveVerifyAndClinit(type_idx, caller, self, false, true);
+ return ResolveVerifyAndClinit(dex::TypeIndex(type_idx), caller, self, false, true);
}
extern "C" mirror::String* artResolveStringFromCode(int32_t string_idx, Thread* self)
diff --git a/runtime/entrypoints_order_test.cc b/runtime/entrypoints_order_test.cc
index b0463d7..1283660 100644
--- a/runtime/entrypoints_order_test.cc
+++ b/runtime/entrypoints_order_test.cc
@@ -94,8 +94,8 @@
EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, opeer, jpeer, sizeof(void*));
EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, jpeer, stack_begin, sizeof(void*));
EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, stack_begin, stack_size, sizeof(void*));
- EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, stack_size, stack_trace_sample, sizeof(void*));
- EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, stack_trace_sample, wait_next, sizeof(void*));
+ EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, stack_size, deps_or_stack_trace_sample, sizeof(void*));
+ EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, deps_or_stack_trace_sample, wait_next, sizeof(void*));
EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, wait_next, monitor_enter_object, sizeof(void*));
EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, monitor_enter_object, top_handle_scope, sizeof(void*));
EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, top_handle_scope, class_loader_override, sizeof(void*));
diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc
index 3e1cbeb..ae9741f 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.cc b/runtime/interpreter/interpreter.cc
index a32c800..1b3d339 100644
--- a/runtime/interpreter/interpreter.cc
+++ b/runtime/interpreter/interpreter.cc
@@ -543,7 +543,7 @@
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
// This is a suspend point. But it's ok since value has been set into shadow_frame.
ObjPtr<mirror::Class> klass = class_linker->ResolveType(
- instr->VRegB_21c(), shadow_frame->GetMethod());
+ dex::TypeIndex(instr->VRegB_21c()), shadow_frame->GetMethod());
DCHECK(klass->IsStringClass());
}
} else {
diff --git a/runtime/interpreter/interpreter_common.cc b/runtime/interpreter/interpreter_common.cc
index cb775cd..72dbe6a 100644
--- a/runtime/interpreter/interpreter_common.cc
+++ b/runtime/interpreter/interpreter_common.cc
@@ -427,7 +427,7 @@
if (!reg->VerifierInstanceOf(field_class.Ptr())) {
// This should never happen.
std::string temp1, temp2, temp3;
- self->ThrowNewExceptionF("Ljava/lang/VirtualMachineError;",
+ self->ThrowNewExceptionF("Ljava/lang/InternalError;",
"Put '%s' that is not instance of field '%s' in '%s'",
reg->GetClass()->GetDescriptor(&temp1),
field_class->GetDescriptor(&temp2),
@@ -922,7 +922,7 @@
ThrowWrongMethodTypeException(check_type.Ptr(), callsite_type.Get());
return false;
}
- } else {
+ } else if (!IsInvokeTransform(handle_kind)) {
if (UNLIKELY(!IsCallerTransformer(callsite_type) &&
!callsite_type->IsConvertible(check_type.Ptr()))) {
ThrowWrongMethodTypeException(check_type.Ptr(), callsite_type.Get());
@@ -990,37 +990,41 @@
CHECK(called_method != nullptr);
}
- bool call_success;
- if (handle_kind == kInvokeTransform) {
- call_success = DoCallTransform<is_range>(called_method,
- callsite_type,
- handle_type,
- self,
- shadow_frame,
- method_handle /* receiver */,
- result,
- arg,
- first_src_reg);
+ if (IsInvokeTransform(handle_kind)) {
+ // There are two cases here - method handles representing regular
+ // transforms and those representing call site transforms. Method
+ // handles for call site transforms adapt their MethodType to match
+ // the call site. For these, the |callee_type| is the same as the
+ // |callsite_type|. The VarargsCollector is such a tranform, its
+ // method type depends on the call site, ie. x(a) or x(a, b), or
+ // x(a, b, c). The VarargsCollector invokes a variable arity method
+ // with the arity arguments in an array.
+ Handle<mirror::MethodType> callee_type =
+ (handle_kind == kInvokeCallSiteTransform) ? callsite_type : handle_type;
+ return DoCallTransform<is_range>(called_method,
+ callsite_type,
+ callee_type,
+ self,
+ shadow_frame,
+ method_handle /* receiver */,
+ result,
+ arg,
+ first_src_reg);
} else {
- call_success = DoCallPolymorphic<is_range>(called_method,
- callsite_type,
- handle_type,
- self,
- shadow_frame,
- result,
- arg,
- first_src_reg,
- handle_kind);
+ return DoCallPolymorphic<is_range>(called_method,
+ callsite_type,
+ handle_type,
+ self,
+ shadow_frame,
+ result,
+ arg,
+ first_src_reg,
+ handle_kind);
}
- if (LIKELY(call_success && ConvertReturnValue(callsite_type, handle_type, result))) {
- return true;
- }
- DCHECK(self->IsExceptionPending());
- return false;
} 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: {
@@ -1097,7 +1101,6 @@
return num_ins;
}
-
inline void PerformCall(Thread* self,
const DexFile::CodeItem* code_item,
ArtMethod* caller_method,
@@ -1251,18 +1254,31 @@
}
PerformCall(self, code_item, shadow_frame.GetMethod(), first_dest_reg, new_shadow_frame, result);
+ if (self->IsExceptionPending()) {
+ return false;
+ }
// If the caller of this signature polymorphic method was a transformer,
// we need to copy the result back out to the emulated stack frame.
- if (is_caller_transformer && !self->IsExceptionPending()) {
- ObjPtr<mirror::EmulatedStackFrame> emulated_stack_frame(
- reinterpret_cast<mirror::EmulatedStackFrame*>(
- shadow_frame.GetVRegReference(first_src_reg)));
+ if (is_caller_transformer) {
+ StackHandleScope<2> hs(self);
+ Handle<mirror::EmulatedStackFrame> emulated_stack_frame(
+ hs.NewHandle(reinterpret_cast<mirror::EmulatedStackFrame*>(
+ shadow_frame.GetVRegReference(first_src_reg))));
+ Handle<mirror::MethodType> emulated_stack_type(hs.NewHandle(emulated_stack_frame->GetType()));
+ JValue local_result;
+ local_result.SetJ(result->GetJ());
- emulated_stack_frame->SetReturnValue(self, *result);
+ if (ConvertReturnValue(emulated_stack_type, target_type, &local_result)) {
+ emulated_stack_frame->SetReturnValue(self, local_result);
+ return true;
+ } else {
+ DCHECK(self->IsExceptionPending());
+ return false;
+ }
+ } else {
+ return ConvertReturnValue(callsite_type, target_type, result);
}
-
- return !self->IsExceptionPending();
}
template <bool is_range>
@@ -1329,14 +1345,14 @@
0 /* first dest reg */,
new_shadow_frame,
result);
+ if (self->IsExceptionPending()) {
+ return false;
+ }
// If the called transformer method we called has returned a value, then we
// need to copy it back to |result|.
- if (!self->IsExceptionPending()) {
- sf->GetReturnValue(self, result);
- }
-
- return !self->IsExceptionPending();
+ sf->GetReturnValue(self, result);
+ return ConvertReturnValue(callsite_type, callee_type, result);
}
template <bool is_range,
@@ -1460,7 +1476,7 @@
ObjPtr<mirror::Object> o = shadow_frame.GetVRegReference(src_reg);
if (do_assignability_check && o != nullptr) {
PointerSize pointer_size = Runtime::Current()->GetClassLinker()->GetImagePointerSize();
- const uint32_t type_idx = params->GetTypeItem(shorty_pos).type_idx_;
+ const dex::TypeIndex type_idx = params->GetTypeItem(shorty_pos).type_idx_;
ObjPtr<mirror::Class> arg_type = method->GetDexCacheResolvedType(type_idx,
pointer_size);
if (arg_type == nullptr) {
@@ -1477,7 +1493,7 @@
if (!o->VerifierInstanceOf(arg_type)) {
// This should never happen.
std::string temp1, temp2;
- self->ThrowNewExceptionF("Ljava/lang/VirtualMachineError;",
+ self->ThrowNewExceptionF("Ljava/lang/InternalError;",
"Invoking %s with bad arg %d, type '%s' not instance of '%s'",
new_shadow_frame->GetMethod()->GetName(), shorty_pos,
o->GetClass()->GetDescriptor(&temp1),
@@ -1568,7 +1584,7 @@
return false;
}
uint16_t type_idx = is_range ? inst->VRegB_3rc() : inst->VRegB_35c();
- ObjPtr<mirror::Class> array_class = ResolveVerifyAndClinit(type_idx,
+ ObjPtr<mirror::Class> array_class = ResolveVerifyAndClinit(dex::TypeIndex(type_idx),
shadow_frame.GetMethod(),
self,
false,
diff --git a/runtime/interpreter/interpreter_switch_impl.cc b/runtime/interpreter/interpreter_switch_impl.cc
index 435ac62..22c0fe0 100644
--- a/runtime/interpreter/interpreter_switch_impl.cc
+++ b/runtime/interpreter/interpreter_switch_impl.cc
@@ -287,7 +287,7 @@
if (!obj_result->VerifierInstanceOf(return_type)) {
// This should never happen.
std::string temp1, temp2;
- self->ThrowNewExceptionF("Ljava/lang/VirtualMachineError;",
+ self->ThrowNewExceptionF("Ljava/lang/InternalError;",
"Returning '%s' that is not instance of return type '%s'",
obj_result->GetClass()->GetDescriptor(&temp1),
return_type->GetDescriptor(&temp2));
@@ -395,7 +395,7 @@
}
case Instruction::CONST_CLASS: {
PREAMBLE();
- ObjPtr<mirror::Class> c = ResolveVerifyAndClinit(inst->VRegB_21c(),
+ ObjPtr<mirror::Class> c = ResolveVerifyAndClinit(dex::TypeIndex(inst->VRegB_21c()),
shadow_frame.GetMethod(),
self,
false,
@@ -434,7 +434,7 @@
}
case Instruction::CHECK_CAST: {
PREAMBLE();
- ObjPtr<mirror::Class> c = ResolveVerifyAndClinit(inst->VRegB_21c(),
+ ObjPtr<mirror::Class> c = ResolveVerifyAndClinit(dex::TypeIndex(inst->VRegB_21c()),
shadow_frame.GetMethod(),
self,
false,
@@ -454,7 +454,7 @@
}
case Instruction::INSTANCE_OF: {
PREAMBLE();
- ObjPtr<mirror::Class> c = ResolveVerifyAndClinit(inst->VRegC_22c(),
+ ObjPtr<mirror::Class> c = ResolveVerifyAndClinit(dex::TypeIndex(inst->VRegC_22c()),
shadow_frame.GetMethod(),
self,
false,
@@ -484,7 +484,7 @@
case Instruction::NEW_INSTANCE: {
PREAMBLE();
ObjPtr<mirror::Object> obj = nullptr;
- ObjPtr<mirror::Class> c = ResolveVerifyAndClinit(inst->VRegB_21c(),
+ ObjPtr<mirror::Class> c = ResolveVerifyAndClinit(dex::TypeIndex(inst->VRegB_21c()),
shadow_frame.GetMethod(),
self,
false,
@@ -495,8 +495,10 @@
obj = mirror::String::AllocEmptyString<true>(self, allocator_type);
} else {
obj = AllocObjectFromCode<do_access_check, true>(
- inst->VRegB_21c(), shadow_frame.GetMethod(), self,
- Runtime::Current()->GetHeap()->GetCurrentAllocator());
+ dex::TypeIndex(inst->VRegB_21c()),
+ shadow_frame.GetMethod(),
+ self,
+ Runtime::Current()->GetHeap()->GetCurrentAllocator());
}
}
if (UNLIKELY(obj == nullptr)) {
@@ -520,7 +522,10 @@
PREAMBLE();
int32_t length = shadow_frame.GetVReg(inst->VRegB_22c(inst_data));
ObjPtr<mirror::Object> obj = AllocArrayFromCode<do_access_check, true>(
- inst->VRegC_22c(), length, shadow_frame.GetMethod(), self,
+ dex::TypeIndex(inst->VRegC_22c()),
+ length,
+ shadow_frame.GetMethod(),
+ self,
Runtime::Current()->GetHeap()->GetCurrentAllocator());
if (UNLIKELY(obj == nullptr)) {
HANDLE_PENDING_EXCEPTION();
@@ -572,7 +577,7 @@
} else if (do_assignability_check && !exception->GetClass()->IsThrowableClass()) {
// This should never happen.
std::string temp;
- self->ThrowNewExceptionF("Ljava/lang/VirtualMachineError;",
+ self->ThrowNewExceptionF("Ljava/lang/InternalError;",
"Throwing '%s' that is not instance of Throwable",
exception->GetClass()->GetDescriptor(&temp));
} else {
diff --git a/runtime/interpreter/mterp/mterp.cc b/runtime/interpreter/mterp/mterp.cc
index 2bd47bb..fbfed40 100644
--- a/runtime/interpreter/mterp/mterp.cc
+++ b/runtime/interpreter/mterp/mterp.cc
@@ -304,7 +304,11 @@
ShadowFrame* shadow_frame,
Thread* self)
REQUIRES_SHARED(Locks::mutator_lock_) {
- mirror::Class* c = ResolveVerifyAndClinit(index, shadow_frame->GetMethod(), self, false, false);
+ mirror::Class* c = ResolveVerifyAndClinit(dex::TypeIndex(index),
+ shadow_frame->GetMethod(),
+ self,
+ false,
+ false);
if (UNLIKELY(c == nullptr)) {
return true;
}
@@ -317,7 +321,11 @@
art::ArtMethod* method,
Thread* self)
REQUIRES_SHARED(Locks::mutator_lock_) {
- ObjPtr<mirror::Class> c = ResolveVerifyAndClinit(index, method, self, false, false);
+ ObjPtr<mirror::Class> c = ResolveVerifyAndClinit(dex::TypeIndex(index),
+ method,
+ self,
+ false,
+ false);
if (UNLIKELY(c == nullptr)) {
return true;
}
@@ -335,7 +343,11 @@
art::ArtMethod* method,
Thread* self)
REQUIRES_SHARED(Locks::mutator_lock_) {
- ObjPtr<mirror::Class> c = ResolveVerifyAndClinit(index, method, self, false, false);
+ ObjPtr<mirror::Class> c = ResolveVerifyAndClinit(dex::TypeIndex(index),
+ method,
+ self,
+ false,
+ false);
if (UNLIKELY(c == nullptr)) {
return false; // Caller will check for pending exception. Return value unimportant.
}
@@ -353,7 +365,7 @@
REQUIRES_SHARED(Locks::mutator_lock_) {
const Instruction* inst = Instruction::At(shadow_frame->GetDexPCPtr());
mirror::Object* obj = nullptr;
- mirror::Class* c = ResolveVerifyAndClinit(inst->VRegB_21c(),
+ mirror::Class* c = ResolveVerifyAndClinit(dex::TypeIndex(inst->VRegB_21c()),
shadow_frame->GetMethod(),
self,
false,
@@ -363,9 +375,10 @@
gc::AllocatorType allocator_type = Runtime::Current()->GetHeap()->GetCurrentAllocator();
obj = mirror::String::AllocEmptyString<true>(self, allocator_type);
} else {
- obj = AllocObjectFromCode<false, true>(
- inst->VRegB_21c(), shadow_frame->GetMethod(), self,
- Runtime::Current()->GetHeap()->GetCurrentAllocator());
+ obj = AllocObjectFromCode<false, true>(dex::TypeIndex(inst->VRegB_21c()),
+ shadow_frame->GetMethod(),
+ self,
+ Runtime::Current()->GetHeap()->GetCurrentAllocator());
}
}
if (UNLIKELY(obj == nullptr)) {
@@ -446,7 +459,7 @@
const Instruction* inst = Instruction::At(dex_pc_ptr);
int32_t length = shadow_frame->GetVReg(inst->VRegB_22c(inst_data));
mirror::Object* obj = AllocArrayFromCode<false, true>(
- inst->VRegC_22c(), length, shadow_frame->GetMethod(), self,
+ dex::TypeIndex(inst->VRegC_22c()), length, shadow_frame->GetMethod(), self,
Runtime::Current()->GetHeap()->GetCurrentAllocator());
if (UNLIKELY(obj == nullptr)) {
return false;
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/jdwp/jdwp_event.cc b/runtime/jdwp/jdwp_event.cc
index fad7d90..5574a11 100644
--- a/runtime/jdwp/jdwp_event.cc
+++ b/runtime/jdwp/jdwp_event.cc
@@ -621,8 +621,8 @@
Thread* const self = Thread::Current();
self->AssertThreadSuspensionIsAllowable();
CHECK(pReq != nullptr);
+ CHECK_EQ(threadId, Dbg::GetThreadSelfId()) << "Only the current thread can suspend itself";
/* send request and possibly suspend ourselves */
- JDWP::ObjectId thread_self_id = Dbg::GetThreadSelfId();
ScopedThreadSuspension sts(self, kWaitingForDebuggerSend);
if (suspend_policy != SP_NONE) {
AcquireJdwpTokenForEvent(threadId);
@@ -631,7 +631,7 @@
{
// Before suspending, we change our state to kSuspended so the debugger sees us as RUNNING.
ScopedThreadStateChange stsc(self, kSuspended);
- SuspendByPolicy(suspend_policy, thread_self_id);
+ SuspendByPolicy(suspend_policy, threadId);
}
}
@@ -658,13 +658,10 @@
}
void JdwpState::AcquireJdwpTokenForEvent(ObjectId threadId) {
- CHECK_NE(Thread::Current(), GetDebugThread()) << "Expected event thread";
- CHECK_NE(debug_thread_id_, threadId) << "Not expected debug thread";
SetWaitForJdwpToken(threadId);
}
void JdwpState::ReleaseJdwpTokenForEvent() {
- CHECK_NE(Thread::Current(), GetDebugThread()) << "Expected event thread";
ClearWaitForJdwpToken();
}
@@ -685,23 +682,28 @@
/* this is held for very brief periods; contention is unlikely */
MutexLock mu(self, jdwp_token_lock_);
- CHECK_NE(jdwp_token_owner_thread_id_, threadId) << "Thread is already holding event thread lock";
+ if (jdwp_token_owner_thread_id_ == threadId) {
+ // Only the debugger thread may already hold the event token. For instance, it may trigger
+ // a CLASS_PREPARE event while processing a command that initializes a class.
+ CHECK_EQ(threadId, debug_thread_id_) << "Non-debugger thread is already holding event token";
+ } else {
+ /*
+ * If another thread is already doing stuff, wait for it. This can
+ * go to sleep indefinitely.
+ */
- /*
- * If another thread is already doing stuff, wait for it. This can
- * go to sleep indefinitely.
- */
- while (jdwp_token_owner_thread_id_ != 0) {
- VLOG(jdwp) << StringPrintf("event in progress (%#" PRIx64 "), %#" PRIx64 " sleeping",
- jdwp_token_owner_thread_id_, threadId);
- waited = true;
- jdwp_token_cond_.Wait(self);
- }
+ while (jdwp_token_owner_thread_id_ != 0) {
+ VLOG(jdwp) << StringPrintf("event in progress (%#" PRIx64 "), %#" PRIx64 " sleeping",
+ jdwp_token_owner_thread_id_, threadId);
+ waited = true;
+ jdwp_token_cond_.Wait(self);
+ }
- if (waited || threadId != debug_thread_id_) {
- VLOG(jdwp) << StringPrintf("event token grabbed (%#" PRIx64 ")", threadId);
+ if (waited || threadId != debug_thread_id_) {
+ VLOG(jdwp) << StringPrintf("event token grabbed (%#" PRIx64 ")", threadId);
+ }
+ jdwp_token_owner_thread_id_ = threadId;
}
- jdwp_token_owner_thread_id_ = threadId;
}
/*
@@ -1224,14 +1226,15 @@
VLOG(jdwp) << " suspend_policy=" << suspend_policy;
}
- if (thread_id == debug_thread_id_) {
+ ObjectId reported_thread_id = thread_id;
+ if (reported_thread_id == debug_thread_id_) {
/*
* JDWP says that, for a class prep in the debugger thread, we
* should set thread to null and if any threads were supposed
* to be suspended then we suspend all other threads.
*/
VLOG(jdwp) << " NOTE: class prepare in debugger thread!";
- thread_id = 0;
+ reported_thread_id = 0;
if (suspend_policy == SP_EVENT_THREAD) {
suspend_policy = SP_ALL;
}
@@ -1244,7 +1247,7 @@
for (const JdwpEvent* pEvent : match_list) {
expandBufAdd1(pReq, pEvent->eventKind);
expandBufAdd4BE(pReq, pEvent->requestId);
- expandBufAddObjectId(pReq, thread_id);
+ expandBufAddObjectId(pReq, reported_thread_id);
expandBufAdd1(pReq, tag);
expandBufAddRefTypeId(pReq, class_id);
expandBufAddUtf8String(pReq, signature);
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/jit_code_cache.cc b/runtime/jit/jit_code_cache.cc
index a26d850..3531852 100644
--- a/runtime/jit/jit_code_cache.cc
+++ b/runtime/jit/jit_code_cache.cc
@@ -80,8 +80,18 @@
std::string error_str;
// Map name specific for android_os_Debug.cpp accounting.
+ // Map in low 4gb to simplify accessing root tables for x86_64.
+ // We could do PC-relative addressing to avoid this problem, but that
+ // would require reserving code and data area before submitting, which
+ // means more windows for the code memory to be RWX.
MemMap* data_map = MemMap::MapAnonymous(
- "data-code-cache", nullptr, max_capacity, kProtAll, false, false, &error_str, use_ashmem);
+ "data-code-cache", nullptr,
+ max_capacity,
+ kProtAll,
+ /* low_4gb */ true,
+ /* reuse */ false,
+ &error_str,
+ use_ashmem);
if (data_map == nullptr) {
std::ostringstream oss;
oss << "Failed to create read write execute cache: " << error_str << " size=" << max_capacity;
@@ -197,34 +207,40 @@
uint8_t* JitCodeCache::CommitCode(Thread* self,
ArtMethod* method,
- const uint8_t* vmap_table,
+ uint8_t* stack_map,
+ uint8_t* roots_data,
size_t frame_size_in_bytes,
size_t core_spill_mask,
size_t fp_spill_mask,
const uint8_t* code,
size_t code_size,
- bool osr) {
+ bool osr,
+ Handle<mirror::ObjectArray<mirror::Object>> roots) {
uint8_t* result = CommitCodeInternal(self,
method,
- vmap_table,
+ stack_map,
+ roots_data,
frame_size_in_bytes,
core_spill_mask,
fp_spill_mask,
code,
code_size,
- osr);
+ osr,
+ roots);
if (result == nullptr) {
// Retry.
GarbageCollectCache(self);
result = CommitCodeInternal(self,
method,
- vmap_table,
+ stack_map,
+ roots_data,
frame_size_in_bytes,
core_spill_mask,
fp_spill_mask,
code,
code_size,
- osr);
+ osr,
+ roots);
}
return result;
}
@@ -243,20 +259,82 @@
return reinterpret_cast<uintptr_t>(code) - RoundUp(sizeof(OatQuickMethodHeader), alignment);
}
+static uint32_t ComputeRootTableSize(uint32_t number_of_roots) {
+ return sizeof(uint32_t) + number_of_roots * sizeof(GcRoot<mirror::Object>);
+}
+
+static uint32_t GetNumberOfRoots(const uint8_t* stack_map) {
+ // The length of the table is stored just before the stack map (and therefore at the end of
+ // the table itself), in order to be able to fetch it from a `stack_map` pointer.
+ return reinterpret_cast<const uint32_t*>(stack_map)[-1];
+}
+
+static void FillRootTableLength(uint8_t* roots_data, uint32_t length) {
+ // Store the length of the table at the end. This will allow fetching it from a `stack_map`
+ // pointer.
+ reinterpret_cast<uint32_t*>(roots_data)[length] = length;
+}
+
+static void FillRootTable(uint8_t* roots_data, Handle<mirror::ObjectArray<mirror::Object>> roots)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ GcRoot<mirror::Object>* gc_roots = reinterpret_cast<GcRoot<mirror::Object>*>(roots_data);
+ const uint32_t length = roots->GetLength();
+ // Put all roots in `roots_data`.
+ for (uint32_t i = 0; i < length; ++i) {
+ ObjPtr<mirror::Object> object = roots->Get(i);
+ if (kIsDebugBuild) {
+ // Ensure the string is strongly interned. b/32995596
+ CHECK(object->IsString());
+ ObjPtr<mirror::String> str = reinterpret_cast<mirror::String*>(object.Ptr());
+ ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+ CHECK(class_linker->GetInternTable()->LookupStrong(Thread::Current(), str) != nullptr);
+ }
+ gc_roots[i] = GcRoot<mirror::Object>(object);
+ }
+ FillRootTableLength(roots_data, length);
+}
+
+static uint8_t* GetRootTable(const void* code_ptr, uint32_t* number_of_roots = nullptr) {
+ OatQuickMethodHeader* method_header = OatQuickMethodHeader::FromCodePointer(code_ptr);
+ uint8_t* data = method_header->GetOptimizedCodeInfoPtr();
+ uint32_t roots = GetNumberOfRoots(data);
+ if (number_of_roots != nullptr) {
+ *number_of_roots = roots;
+ }
+ return data - ComputeRootTableSize(roots);
+}
+
+void JitCodeCache::SweepRootTables(IsMarkedVisitor* visitor) {
+ MutexLock mu(Thread::Current(), lock_);
+ for (const auto& entry : method_code_map_) {
+ uint32_t number_of_roots = 0;
+ uint8_t* roots_data = GetRootTable(entry.first, &number_of_roots);
+ GcRoot<mirror::Object>* roots = reinterpret_cast<GcRoot<mirror::Object>*>(roots_data);
+ for (uint32_t i = 0; i < number_of_roots; ++i) {
+ // This does not need a read barrier because this is called by GC.
+ mirror::Object* object = roots[i].Read<kWithoutReadBarrier>();
+ DCHECK(object != nullptr);
+ mirror::Object* new_object = visitor->IsMarked(object);
+ // We know the string is marked because it's a strongly-interned string that
+ // is always alive. The IsMarked implementation of the CMS collector returns
+ // null for newly allocated objects, but we know those haven't moved. Therefore,
+ // only update the entry if we get a different non-null string.
+ // TODO: Do not use IsMarked for j.l.Class, and adjust once we move this method
+ // out of the weak access/creation pause. b/32167580
+ if (new_object != nullptr && new_object != object) {
+ DCHECK(new_object->IsString());
+ roots[i] = GcRoot<mirror::Object>(new_object);
+ }
+ }
+ }
+}
+
void JitCodeCache::FreeCode(const void* code_ptr, ArtMethod* method ATTRIBUTE_UNUSED) {
uintptr_t allocation = FromCodeToAllocation(code_ptr);
- const OatQuickMethodHeader* method_header = OatQuickMethodHeader::FromCodePointer(code_ptr);
// Notify native debugger that we are about to remove the code.
// It does nothing if we are not using native debugger.
DeleteJITCodeEntryForAddress(reinterpret_cast<uintptr_t>(code_ptr));
-
- // Use the offset directly to prevent sanity check that the method is
- // compiled with optimizing.
- // TODO(ngeoffray): Clean up.
- if (method_header->vmap_table_offset_ != 0) {
- const uint8_t* data = method_header->code_ - method_header->vmap_table_offset_;
- FreeData(const_cast<uint8_t*>(data));
- }
+ FreeData(GetRootTable(code_ptr));
FreeCode(reinterpret_cast<uint8_t*>(allocation));
}
@@ -308,17 +386,21 @@
uint8_t* JitCodeCache::CommitCodeInternal(Thread* self,
ArtMethod* method,
- const uint8_t* vmap_table,
+ uint8_t* stack_map,
+ uint8_t* roots_data,
size_t frame_size_in_bytes,
size_t core_spill_mask,
size_t fp_spill_mask,
const uint8_t* code,
size_t code_size,
- bool osr) {
+ bool osr,
+ Handle<mirror::ObjectArray<mirror::Object>> roots) {
+ DCHECK(stack_map != nullptr);
size_t alignment = GetInstructionSetAlignment(kRuntimeISA);
// Ensure the header ends up at expected instruction alignment.
size_t header_size = RoundUp(sizeof(OatQuickMethodHeader), alignment);
size_t total_size = header_size + code_size;
+ const uint32_t num_roots = roots->GetLength();
OatQuickMethodHeader* method_header = nullptr;
uint8_t* code_ptr = nullptr;
@@ -331,6 +413,9 @@
ScopedCodeCacheWrite scc(code_map_.get());
memory = AllocateCode(total_size);
if (memory == nullptr) {
+ // Fill root table length so that ClearData works correctly in case of failure. Otherwise
+ // the length will be 0 and cause incorrect DCHECK failure.
+ FillRootTableLength(roots_data, num_roots);
return nullptr;
}
code_ptr = memory + header_size;
@@ -338,21 +423,29 @@
std::copy(code, code + code_size, code_ptr);
method_header = OatQuickMethodHeader::FromCodePointer(code_ptr);
new (method_header) OatQuickMethodHeader(
- (vmap_table == nullptr) ? 0 : code_ptr - vmap_table,
+ code_ptr - stack_map,
frame_size_in_bytes,
core_spill_mask,
fp_spill_mask,
code_size);
+ // Flush caches before we remove write permission because on some ARMv8 hardware,
+ // flushing caches require write permissions.
+ //
+ // For reference, here are kernel patches discussing about this issue:
+ // https://android.googlesource.com/kernel/msm/%2B/0e7f7bcc3fc87489cda5aa6aff8ce40eed912279
+ // https://patchwork.kernel.org/patch/9047921/
+ FlushInstructionCache(reinterpret_cast<char*>(code_ptr),
+ reinterpret_cast<char*>(code_ptr + code_size));
}
- FlushInstructionCache(reinterpret_cast<char*>(code_ptr),
- reinterpret_cast<char*>(code_ptr + code_size));
number_of_compilations_++;
}
// We need to update the entry point in the runnable state for the instrumentation.
{
MutexLock mu(self, lock_);
method_code_map_.Put(code_ptr, method);
+ // Fill the root table before updating the entry point.
+ FillRootTable(roots_data, roots);
if (osr) {
number_of_osr_compilations_++;
osr_code_map_.Put(method, code_ptr);
@@ -403,13 +496,26 @@
return used_memory_for_data_;
}
-void JitCodeCache::ClearData(Thread* self, void* data) {
- MutexLock mu(self, lock_);
- FreeData(reinterpret_cast<uint8_t*>(data));
+static const uint8_t* FromStackMapToRoots(const uint8_t* stack_map_data) {
+ return stack_map_data - ComputeRootTableSize(GetNumberOfRoots(stack_map_data));
}
-uint8_t* JitCodeCache::ReserveData(Thread* self, size_t size, ArtMethod* method) {
- size = RoundUp(size, sizeof(void*));
+void JitCodeCache::ClearData(Thread* self,
+ uint8_t* stack_map_data,
+ uint8_t* roots_data) {
+ DCHECK_EQ(FromStackMapToRoots(stack_map_data), roots_data);
+ MutexLock mu(self, lock_);
+ FreeData(reinterpret_cast<uint8_t*>(roots_data));
+}
+
+void JitCodeCache::ReserveData(Thread* self,
+ size_t stack_map_size,
+ size_t number_of_roots,
+ ArtMethod* method,
+ uint8_t** stack_map_data,
+ uint8_t** roots_data) {
+ size_t table_size = ComputeRootTableSize(number_of_roots);
+ size_t size = RoundUp(stack_map_size + table_size, sizeof(void*));
uint8_t* result = nullptr;
{
@@ -436,7 +542,8 @@
<< " for stack maps of "
<< ArtMethod::PrettyMethod(method);
}
- return result;
+ *roots_data = result;
+ *stack_map_data = result + table_size;
}
class MarkCodeVisitor FINAL : public StackVisitor {
diff --git a/runtime/jit/jit_code_cache.h b/runtime/jit/jit_code_cache.h
index e15c93a..40112fe 100644
--- a/runtime/jit/jit_code_cache.h
+++ b/runtime/jit/jit_code_cache.h
@@ -92,13 +92,15 @@
// Allocate and write code and its metadata to the code cache.
uint8_t* CommitCode(Thread* self,
ArtMethod* method,
- const uint8_t* vmap_table,
+ uint8_t* stack_map,
+ uint8_t* roots_data,
size_t frame_size_in_bytes,
size_t core_spill_mask,
size_t fp_spill_mask,
const uint8_t* code,
size_t code_size,
- bool osr)
+ bool osr,
+ Handle<mirror::ObjectArray<mirror::Object>> roots)
REQUIRES_SHARED(Locks::mutator_lock_)
REQUIRES(!lock_);
@@ -108,13 +110,19 @@
// Return true if the code cache contains this method.
bool ContainsMethod(ArtMethod* method) REQUIRES(!lock_);
- // Reserve a region of data of size at least "size". Returns null if there is no more room.
- uint8_t* ReserveData(Thread* self, size_t size, ArtMethod* method)
+ // Allocate a region of data that contain `size` bytes, and potentially space
+ // for storing `number_of_roots` roots. Returns null if there is no more room.
+ void ReserveData(Thread* self,
+ size_t size,
+ size_t number_of_roots,
+ ArtMethod* method,
+ uint8_t** stack_map_data,
+ uint8_t** roots_data)
REQUIRES_SHARED(Locks::mutator_lock_)
REQUIRES(!lock_);
// Clear data from the data portion of the code cache.
- void ClearData(Thread* self, void* data)
+ void ClearData(Thread* self, uint8_t* stack_map_data, uint8_t* roots_data)
REQUIRES_SHARED(Locks::mutator_lock_)
REQUIRES(!lock_);
@@ -188,6 +196,10 @@
bool IsOsrCompiled(ArtMethod* method) REQUIRES(!lock_);
+ void SweepRootTables(IsMarkedVisitor* visitor)
+ REQUIRES(!lock_)
+ REQUIRES_SHARED(Locks::mutator_lock_);
+
private:
// Take ownership of maps.
JitCodeCache(MemMap* code_map,
@@ -201,13 +213,15 @@
// allocation fails. Return null if the allocation fails.
uint8_t* CommitCodeInternal(Thread* self,
ArtMethod* method,
- const uint8_t* vmap_table,
+ uint8_t* stack_map,
+ uint8_t* roots_data,
size_t frame_size_in_bytes,
size_t core_spill_mask,
size_t fp_spill_mask,
const uint8_t* code,
size_t code_size,
- bool osr)
+ bool osr,
+ Handle<mirror::ObjectArray<mirror::Object>> roots)
REQUIRES(!lock_)
REQUIRES_SHARED(Locks::mutator_lock_);
diff --git a/runtime/jit/offline_profiling_info.cc b/runtime/jit/offline_profiling_info.cc
index f535151..6f2a8c6 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;
@@ -235,7 +235,7 @@
AddUintToBuffer(&buffer, method_it);
}
for (auto class_id : dex_data.class_set) {
- AddUintToBuffer(&buffer, class_id);
+ AddUintToBuffer(&buffer, class_id.index_);
}
DCHECK_EQ(required_capacity, buffer.size())
<< "Failed to add the expected number of bytes in the buffer";
@@ -282,12 +282,12 @@
bool ProfileCompilationInfo::AddClassIndex(const std::string& dex_location,
uint32_t checksum,
- uint16_t class_idx) {
+ dex::TypeIndex 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, dex::TypeIndex(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, dex::TypeIndex 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();
+ const std::set<dex::TypeIndex>& classes = info_it->second.class_set;
+ 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, dex::TypeIndex(type_idx));
}
}
return info.Save(fd);
diff --git a/runtime/jit/offline_profiling_info.h b/runtime/jit/offline_profiling_info.h
index fdca078..4136488 100644
--- a/runtime/jit/offline_profiling_info.h
+++ b/runtime/jit/offline_profiling_info.h
@@ -23,6 +23,7 @@
#include "atomic.h"
#include "dex_cache_resolved_classes.h"
#include "dex_file.h"
+#include "dex_file_types.h"
#include "method_reference.h"
#include "safe_map.h"
@@ -65,8 +66,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, dex::TypeIndex 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
@@ -104,7 +105,7 @@
explicit DexFileData(uint32_t location_checksum) : checksum(location_checksum) {}
uint32_t checksum;
std::set<uint16_t> method_set;
- std::set<uint16_t> class_set;
+ std::set<dex::TypeIndex> class_set;
bool operator==(const DexFileData& other) const {
return checksum == other.checksum && method_set == other.method_set;
@@ -115,7 +116,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, dex::TypeIndex type_idx);
bool AddResolvedClasses(const DexCacheResolvedClasses& classes);
// Parsing functionality.
diff --git a/runtime/method_handles.h b/runtime/method_handles.h
index 54c772a..d0a4902 100644
--- a/runtime/method_handles.h
+++ b/runtime/method_handles.h
@@ -46,12 +46,13 @@
kInvokeStatic,
kInvokeInterface,
kInvokeTransform,
+ kInvokeCallSiteTransform,
kInstanceGet,
kInstancePut,
kStaticGet,
kStaticPut,
kLastValidKind = kStaticPut,
- kLastInvokeKind = kInvokeTransform
+ kLastInvokeKind = kInvokeCallSiteTransform
};
// Whether the given method handle kind is some variant of an invoke.
@@ -59,6 +60,11 @@
return handle_kind <= kLastInvokeKind;
}
+// Whether the given method handle kind is some variant of a tranform.
+inline bool IsInvokeTransform(const MethodHandleKind handle_kind) {
+ return handle_kind == kInvokeTransform || handle_kind == kInvokeCallSiteTransform;
+}
+
// Returns true if there is a possible conversion from |from| to |to|
// for a MethodHandle parameter.
bool IsParameterTypeConvertible(ObjPtr<mirror::Class> from,
diff --git a/runtime/mirror/class-inl.h b/runtime/mirror/class-inl.h
index bbdb2af..aa5da2e 100644
--- a/runtime/mirror/class-inl.h
+++ b/runtime/mirror/class-inl.h
@@ -372,7 +372,7 @@
// to access the field if the FieldId specifies an accessible subclass of the declaring
// class rather than the declaring class itself.
ObjPtr<DexCache> referrer_dex_cache = use_referrers_cache ? this->GetDexCache() : dex_cache;
- uint32_t class_idx = referrer_dex_cache->GetDexFile()->GetFieldId(field_idx).class_idx_;
+ dex::TypeIndex class_idx = referrer_dex_cache->GetDexFile()->GetFieldId(field_idx).class_idx_;
// The referenced class has already been resolved with the field, but may not be in the dex
// cache. Use LookupResolveType here to search the class table if it is not in the dex cache.
// should be no thread suspension due to the class being resolved.
@@ -410,7 +410,7 @@
// to access the method if the MethodId specifies an accessible subclass of the declaring
// class rather than the declaring class itself.
ObjPtr<DexCache> referrer_dex_cache = use_referrers_cache ? this->GetDexCache() : dex_cache;
- uint32_t class_idx = referrer_dex_cache->GetDexFile()->GetMethodId(method_idx).class_idx_;
+ dex::TypeIndex class_idx = referrer_dex_cache->GetDexFile()->GetMethodId(method_idx).class_idx_;
// The referenced class has already been resolved with the method, but may not be in the dex
// cache.
ObjPtr<Class> dex_access_to = Runtime::Current()->GetClassLinker()->LookupResolvedType(
@@ -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);
}
@@ -895,7 +894,8 @@
klass->SetClassSize(class_size_);
klass->SetPrimitiveType(Primitive::kPrimNot); // Default to not being primitive.
klass->SetDexClassDefIndex(DexFile::kDexNoIndex16); // Default to no valid class def index.
- klass->SetDexTypeIndex(DexFile::kDexNoIndex16); // Default to no valid type index.
+ klass->SetDexTypeIndex(dex::TypeIndex(DexFile::kDexNoIndex16)); // Default to no valid type
+ // index.
// Default to force slow path until initialized.
klass->SetObjectSizeAllocFastPath(std::numeric_limits<uint32_t>::max());
}
diff --git a/runtime/mirror/class.cc b/runtime/mirror/class.cc
index db46027..0cfe29b 100644
--- a/runtime/mirror/class.cc
+++ b/runtime/mirror/class.cc
@@ -923,7 +923,7 @@
return &GetDexFile().GetClassDef(class_def_idx);
}
-uint16_t Class::GetDirectInterfaceTypeIdx(uint32_t idx) {
+dex::TypeIndex Class::GetDirectInterfaceTypeIdx(uint32_t idx) {
DCHECK(!IsPrimitive());
DCHECK(!IsArrayClass());
return GetInterfaceTypeList()->GetTypeItem(idx).type_idx_;
@@ -947,10 +947,11 @@
DCHECK(interfaces != nullptr);
return interfaces->Get(idx);
} else {
- uint16_t type_idx = klass->GetDirectInterfaceTypeIdx(idx);
+ dex::TypeIndex type_idx = klass->GetDirectInterfaceTypeIdx(idx);
ObjPtr<Class> interface = klass->GetDexCache()->GetResolvedType(type_idx);
if (interface == nullptr) {
- interface = Runtime::Current()->GetClassLinker()->ResolveType(klass->GetDexFile(), type_idx,
+ interface = Runtime::Current()->GetClassLinker()->ResolveType(klass->GetDexFile(),
+ type_idx,
klass.Get());
CHECK(interface != nullptr || self->IsExceptionPending());
}
@@ -1130,10 +1131,12 @@
return depth;
}
-uint32_t Class::FindTypeIndexInOtherDexFile(const DexFile& dex_file) {
+dex::TypeIndex Class::FindTypeIndexInOtherDexFile(const DexFile& dex_file) {
std::string temp;
const DexFile::TypeId* type_id = dex_file.FindTypeId(GetDescriptor(&temp));
- return (type_id == nullptr) ? DexFile::kDexNoIndex : dex_file.GetIndexForTypeId(*type_id);
+ return (type_id == nullptr)
+ ? dex::TypeIndex(DexFile::kDexNoIndex)
+ : dex_file.GetIndexForTypeId(*type_id);
}
template <PointerSize kPointerSize, bool kTransactionActive>
diff --git a/runtime/mirror/class.h b/runtime/mirror/class.h
index 711914d..792f626 100644
--- a/runtime/mirror/class.h
+++ b/runtime/mirror/class.h
@@ -20,6 +20,7 @@
#include "base/enums.h"
#include "base/iteration_range.h"
#include "dex_file.h"
+#include "dex_file_types.h"
#include "class_flags.h"
#include "gc_root.h"
#include "gc/allocator_type.h"
@@ -1148,16 +1149,17 @@
SetField32<false>(OFFSET_OF_OBJECT_MEMBER(Class, dex_class_def_idx_), class_def_idx);
}
- uint16_t GetDexTypeIndex() REQUIRES_SHARED(Locks::mutator_lock_) {
- return GetField32(OFFSET_OF_OBJECT_MEMBER(Class, dex_type_idx_));
+ dex::TypeIndex GetDexTypeIndex() REQUIRES_SHARED(Locks::mutator_lock_) {
+ return dex::TypeIndex(
+ static_cast<uint16_t>(GetField32(OFFSET_OF_OBJECT_MEMBER(Class, dex_type_idx_))));
}
- void SetDexTypeIndex(uint16_t type_idx) REQUIRES_SHARED(Locks::mutator_lock_) {
+ void SetDexTypeIndex(dex::TypeIndex type_idx) REQUIRES_SHARED(Locks::mutator_lock_) {
// Not called within a transaction.
- SetField32<false>(OFFSET_OF_OBJECT_MEMBER(Class, dex_type_idx_), type_idx);
+ SetField32<false>(OFFSET_OF_OBJECT_MEMBER(Class, dex_type_idx_), type_idx.index_);
}
- uint32_t FindTypeIndexInOtherDexFile(const DexFile& dex_file)
+ dex::TypeIndex FindTypeIndexInOtherDexFile(const DexFile& dex_file)
REQUIRES_SHARED(Locks::mutator_lock_);
static Class* GetJavaLangClass() REQUIRES_SHARED(Locks::mutator_lock_) {
@@ -1198,7 +1200,7 @@
ALWAYS_INLINE uint32_t NumDirectInterfaces() REQUIRES_SHARED(Locks::mutator_lock_);
- uint16_t GetDirectInterfaceTypeIdx(uint32_t idx) REQUIRES_SHARED(Locks::mutator_lock_);
+ dex::TypeIndex GetDirectInterfaceTypeIdx(uint32_t idx) REQUIRES_SHARED(Locks::mutator_lock_);
static ObjPtr<Class> GetDirectInterface(Thread* self,
Handle<Class> klass,
diff --git a/runtime/mirror/dex_cache-inl.h b/runtime/mirror/dex_cache-inl.h
index c7a123b..d903f71 100644
--- a/runtime/mirror/dex_cache-inl.h
+++ b/runtime/mirror/dex_cache-inl.h
@@ -69,15 +69,15 @@
}
}
-inline Class* DexCache::GetResolvedType(uint32_t type_idx) {
- DCHECK_LT(type_idx, NumResolvedTypes());
- return GetResolvedTypes()[type_idx].Read();
+inline Class* DexCache::GetResolvedType(dex::TypeIndex type_idx) {
+ DCHECK_LT(type_idx.index_, NumResolvedTypes());
+ return GetResolvedTypes()[type_idx.index_].Read();
}
-inline void DexCache::SetResolvedType(uint32_t type_idx, ObjPtr<Class> resolved) {
- DCHECK_LT(type_idx, NumResolvedTypes()); // NOTE: Unchecked, i.e. not throwing AIOOB.
+inline void DexCache::SetResolvedType(dex::TypeIndex type_idx, ObjPtr<Class> resolved) {
+ DCHECK_LT(type_idx.index_, NumResolvedTypes()); // NOTE: Unchecked, i.e. not throwing AIOOB.
// TODO default transaction support.
- GetResolvedTypes()[type_idx] = GcRoot<Class>(resolved);
+ GetResolvedTypes()[type_idx.index_] = GcRoot<Class>(resolved);
// TODO: Fine-grained marking, so that we don't need to go through all arrays in full.
Runtime::Current()->GetHeap()->WriteBarrierEveryFieldOf(this);
}
diff --git a/runtime/mirror/dex_cache.h b/runtime/mirror/dex_cache.h
index 1ae694d..7d82d3a 100644
--- a/runtime/mirror/dex_cache.h
+++ b/runtime/mirror/dex_cache.h
@@ -21,6 +21,7 @@
#include "art_field.h"
#include "art_method.h"
#include "class.h"
+#include "dex_file_types.h"
#include "object.h"
#include "object_array.h"
@@ -223,9 +224,9 @@
// the string isn't kept live.
void ClearString(uint32_t string_idx) REQUIRES_SHARED(Locks::mutator_lock_);
- Class* GetResolvedType(uint32_t type_idx) REQUIRES_SHARED(Locks::mutator_lock_);
+ Class* GetResolvedType(dex::TypeIndex type_idx) REQUIRES_SHARED(Locks::mutator_lock_);
- void SetResolvedType(uint32_t type_idx, ObjPtr<Class> resolved)
+ void SetResolvedType(dex::TypeIndex type_idx, ObjPtr<Class> resolved)
REQUIRES_SHARED(Locks::mutator_lock_);
ALWAYS_INLINE ArtMethod* GetResolvedMethod(uint32_t method_idx, PointerSize ptr_size)
diff --git a/runtime/mirror/emulated_stack_frame.h b/runtime/mirror/emulated_stack_frame.h
index 9fa06b7..d83a536 100644
--- a/runtime/mirror/emulated_stack_frame.h
+++ b/runtime/mirror/emulated_stack_frame.h
@@ -58,6 +58,10 @@
// Sets the return value slot of this emulated stack frame to |value|.
void SetReturnValue(Thread* self, const JValue& value) REQUIRES_SHARED(Locks::mutator_lock_);
+ mirror::MethodType* GetType() REQUIRES_SHARED(Locks::mutator_lock_) {
+ return GetFieldObject<MethodType>(OFFSET_OF_OBJECT_MEMBER(EmulatedStackFrame, type_));
+ }
+
static void SetClass(Class* klass) REQUIRES_SHARED(Locks::mutator_lock_);
static void ResetClass() REQUIRES_SHARED(Locks::mutator_lock_);
static void VisitRoots(RootVisitor* visitor) REQUIRES_SHARED(Locks::mutator_lock_);
@@ -67,10 +71,6 @@
return static_class_.Read();
}
- mirror::MethodType* GetType() REQUIRES_SHARED(Locks::mutator_lock_) {
- return GetFieldObject<MethodType>(OFFSET_OF_OBJECT_MEMBER(EmulatedStackFrame, type_));
- }
-
mirror::ObjectArray<mirror::Object>* GetReferences() REQUIRES_SHARED(Locks::mutator_lock_) {
return GetFieldObject<mirror::ObjectArray<mirror::Object>>(
OFFSET_OF_OBJECT_MEMBER(EmulatedStackFrame, references_));
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/mirror/object_test.cc b/runtime/mirror/object_test.cc
index 5bf254d..4b47f7f 100644
--- a/runtime/mirror/object_test.cc
+++ b/runtime/mirror/object_test.cc
@@ -313,7 +313,7 @@
ArtMethod* sort = java_util_Arrays->FindDirectMethod("sort", "([I)V", kRuntimePointerSize);
const DexFile::TypeId* type_id = java_lang_dex_file_->FindTypeId("[I");
ASSERT_TRUE(type_id != nullptr);
- uint32_t type_idx = java_lang_dex_file_->GetIndexForTypeId(*type_id);
+ dex::TypeIndex type_idx = java_lang_dex_file_->GetIndexForTypeId(*type_id);
Object* array = CheckAndAllocArrayFromCodeInstrumented(
type_idx, 3, sort, Thread::Current(), false,
Runtime::Current()->GetHeap()->GetCurrentAllocator());
diff --git a/runtime/mirror/throwable.cc b/runtime/mirror/throwable.cc
index b866a63..ade4e87 100644
--- a/runtime/mirror/throwable.cc
+++ b/runtime/mirror/throwable.cc
@@ -104,7 +104,7 @@
CHECK_EQ(array_len % 2, 0);
const auto depth = array_len / 2;
if (depth == 0) {
- result += "(Throwable with empty stack trace)";
+ result += "(Throwable with empty stack trace)\n";
} else {
const PointerSize ptr_size = Runtime::Current()->GetClassLinker()->GetImagePointerSize();
for (int32_t i = 0; i < depth; ++i) {
@@ -124,7 +124,7 @@
ObjPtr<ObjectArray<StackTraceElement>> ste_array =
ObjPtr<ObjectArray<StackTraceElement>>::DownCast(stack_trace);
if (ste_array->GetLength() == 0) {
- result += "(Throwable with empty stack trace)";
+ result += "(Throwable with empty stack trace)\n";
} else {
for (int32_t i = 0; i < ste_array->GetLength(); ++i) {
StackTraceElement* ste = ste_array->Get(i);
@@ -139,7 +139,7 @@
}
}
} else {
- result += "(Throwable with no stack trace)";
+ result += "(Throwable with no stack trace)\n";
}
}
ObjPtr<Throwable> cause = GetFieldObject<Throwable>(OFFSET_OF_OBJECT_MEMBER(Throwable, cause_));
diff --git a/runtime/native/dalvik_system_DexFile.cc b/runtime/native/dalvik_system_DexFile.cc
index df0849a..1a77072 100644
--- a/runtime/native/dalvik_system_DexFile.cc
+++ b/runtime/native/dalvik_system_DexFile.cc
@@ -413,33 +413,7 @@
OatFileAssistant oat_file_assistant(filename.c_str(), target_instruction_set,
false /* load_executable */);
-
- std::ostringstream status;
- bool oat_file_exists = false;
- bool odex_file_exists = false;
- if (oat_file_assistant.OatFileExists()) {
- oat_file_exists = true;
- status << *oat_file_assistant.OatFileName() << " [compilation_filter=";
- status << CompilerFilter::NameOfFilter(oat_file_assistant.OatFileCompilerFilter());
- status << ", status=" << oat_file_assistant.OatFileStatus();
- }
-
- if (oat_file_assistant.OdexFileExists()) {
- odex_file_exists = true;
- if (oat_file_exists) {
- status << "] ";
- }
- status << *oat_file_assistant.OdexFileName() << " [compilation_filter=";
- status << CompilerFilter::NameOfFilter(oat_file_assistant.OdexFileCompilerFilter());
- status << ", status=" << oat_file_assistant.OdexFileStatus();
- }
-
- if (!oat_file_exists && !odex_file_exists) {
- status << "invalid[";
- }
-
- status << "]";
- return env->NewStringUTF(status.str().c_str());
+ return env->NewStringUTF(oat_file_assistant.GetStatusDump().c_str());
}
static jint DexFile_getDexOptNeeded(JNIEnv* env,
diff --git a/runtime/native/dalvik_system_VMRuntime.cc b/runtime/native/dalvik_system_VMRuntime.cc
index 866dc7f..48feb11 100644
--- a/runtime/native/dalvik_system_VMRuntime.cc
+++ b/runtime/native/dalvik_system_VMRuntime.cc
@@ -34,6 +34,7 @@
#include "common_throws.h"
#include "debugger.h"
#include "dex_file-inl.h"
+#include "dex_file_types.h"
#include "gc/accounting/card_table-inl.h"
#include "gc/allocator/dlmalloc.h"
#include "gc/heap.h"
@@ -305,7 +306,7 @@
// Based on ClassLinker::ResolveType.
static void PreloadDexCachesResolveType(Thread* self,
ObjPtr<mirror::DexCache> dex_cache,
- uint32_t type_idx)
+ dex::TypeIndex type_idx)
REQUIRES_SHARED(Locks::mutator_lock_) {
ObjPtr<mirror::Class> klass = dex_cache->GetResolvedType(type_idx);
if (klass != nullptr) {
@@ -455,7 +456,7 @@
}
}
for (size_t j = 0; j < dex_cache->NumResolvedTypes(); j++) {
- ObjPtr<mirror::Class> klass = dex_cache->GetResolvedType(j);
+ ObjPtr<mirror::Class> klass = dex_cache->GetResolvedType(dex::TypeIndex(j));
if (klass != nullptr) {
filled->num_types++;
}
@@ -519,7 +520,7 @@
if (kPreloadDexCachesTypes) {
for (size_t j = 0; j < dex_cache->NumResolvedTypes(); j++) {
- PreloadDexCachesResolveType(soa.Self(), dex_cache.Get(), j);
+ PreloadDexCachesResolveType(soa.Self(), dex_cache.Get(), dex::TypeIndex(j));
}
}
diff --git a/runtime/native/java_lang_DexCache.cc b/runtime/native/java_lang_DexCache.cc
index 71379a5..f6de593 100644
--- a/runtime/native/java_lang_DexCache.cc
+++ b/runtime/native/java_lang_DexCache.cc
@@ -17,6 +17,7 @@
#include "java_lang_DexCache.h"
#include "dex_file.h"
+#include "dex_file_types.h"
#include "jni_internal.h"
#include "mirror/class-inl.h"
#include "mirror/dex_cache-inl.h"
@@ -53,7 +54,7 @@
ScopedFastNativeObjectAccess soa(env);
ObjPtr<mirror::DexCache> dex_cache = soa.Decode<mirror::DexCache>(javaDexCache);
CHECK_LT(static_cast<size_t>(type_index), dex_cache->NumResolvedTypes());
- return soa.AddLocalReference<jobject>(dex_cache->GetResolvedType(type_index));
+ return soa.AddLocalReference<jobject>(dex_cache->GetResolvedType(dex::TypeIndex(type_index)));
}
static jobject DexCache_getResolvedString(JNIEnv* env, jobject javaDexCache, jint string_index) {
@@ -68,7 +69,7 @@
ScopedFastNativeObjectAccess soa(env);
ObjPtr<mirror::DexCache> dex_cache = soa.Decode<mirror::DexCache>(javaDexCache);
CHECK_LT(static_cast<size_t>(type_index), dex_cache->NumResolvedTypes());
- dex_cache->SetResolvedType(type_index, soa.Decode<mirror::Class>(type));
+ dex_cache->SetResolvedType(dex::TypeIndex(type_index), soa.Decode<mirror::Class>(type));
}
static void DexCache_setResolvedString(JNIEnv* env, jobject javaDexCache, jint string_index,
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/oat_file.cc b/runtime/oat_file.cc
index c14b616..bdf8b0e 100644
--- a/runtime/oat_file.cc
+++ b/runtime/oat_file.cc
@@ -38,6 +38,7 @@
#include "base/stl_util.h"
#include "base/systrace.h"
#include "base/unix_file/fd_file.h"
+#include "dex_file_types.h"
#include "elf_file.h"
#include "elf_utils.h"
#include "gc_root.h"
@@ -718,7 +719,7 @@
dlopen_handle_ = android_dlopen_ext(absolute_path.get(), RTLD_NOW, &extinfo);
#else
UNUSED(oat_file_begin);
- static_assert(!kIsTargetBuild, "host_dlopen_handles_ will leak handles");
+ static_assert(!kIsTargetBuild || kIsTargetLinux, "host_dlopen_handles_ will leak handles");
MutexLock mu(Thread::Current(), *Locks::host_dlopen_handles_lock_);
dlopen_handle_ = dlopen(absolute_path.get(), RTLD_NOW);
if (dlopen_handle_ != nullptr) {
@@ -1252,13 +1253,14 @@
if (lookup_table_data_ + TypeLookupTable::RawDataLength(num_class_defs) > GetOatFile()->End()) {
LOG(WARNING) << "found truncated lookup table in " << dex_file_location_;
} else {
- lookup_table_.reset(TypeLookupTable::Open(dex_file_pointer_,
- lookup_table_data_,
- num_class_defs));
+ lookup_table_ = TypeLookupTable::Open(dex_file_pointer_, lookup_table_data_, num_class_defs);
}
}
}
+OatFile::OatDexFile::OatDexFile(std::unique_ptr<TypeLookupTable>&& lookup_table)
+ : lookup_table_(std::move(lookup_table)) {}
+
OatFile::OatDexFile::~OatDexFile() {}
size_t OatFile::OatDexFile::FileSize() const {
@@ -1342,7 +1344,7 @@
}
const DexFile::TypeId* type_id = dex_file.FindTypeId(descriptor);
if (type_id != nullptr) {
- uint16_t type_idx = dex_file.GetIndexForTypeId(*type_id);
+ dex::TypeIndex type_idx = dex_file.GetIndexForTypeId(*type_id);
return dex_file.FindClassDef(type_idx);
}
return nullptr;
@@ -1540,7 +1542,7 @@
bool* found) {
DCHECK_NE(class_def_idx, DexFile::kDexNoIndex16);
const OatFile::OatDexFile* oat_dex_file = dex_file.GetOatDexFile();
- if (oat_dex_file == nullptr) {
+ if (oat_dex_file == nullptr || oat_dex_file->GetOatFile() == nullptr) {
*found = false;
return OatFile::OatClass::Invalid();
}
@@ -1548,4 +1550,8 @@
return oat_dex_file->GetOatClass(class_def_idx);
}
+void OatFile::OatDexFile::AssertAotCompiler() {
+ CHECK(Runtime::Current()->IsAotCompiler());
+}
+
} // namespace art
diff --git a/runtime/oat_file.h b/runtime/oat_file.h
index 63a0e14..29add5b 100644
--- a/runtime/oat_file.h
+++ b/runtime/oat_file.h
@@ -384,7 +384,13 @@
// Opens the DexFile referred to by this OatDexFile from within the containing OatFile.
std::unique_ptr<const DexFile> OpenDexFile(std::string* error_msg) const;
+ // May return null if the OatDexFile only contains a type lookup table. This case only happens
+ // for the compiler to speed up compilation.
const OatFile* GetOatFile() const {
+ // Avoid pulling in runtime.h in the header file.
+ if (kIsDebugBuild && oat_file_ == nullptr) {
+ AssertAotCompiler();
+ }
return oat_file_;
}
@@ -436,6 +442,9 @@
~OatDexFile();
+ // Create only with a type lookup table, used by the compiler to speed up compilation.
+ explicit OatDexFile(std::unique_ptr<TypeLookupTable>&& lookup_table);
+
private:
OatDexFile(const OatFile* oat_file,
const std::string& dex_file_location,
@@ -446,14 +455,16 @@
const uint32_t* oat_class_offsets_pointer,
uint8_t* dex_cache_arrays);
- const OatFile* const oat_file_;
+ static void AssertAotCompiler();
+
+ const OatFile* const oat_file_ = nullptr;
const std::string dex_file_location_;
const std::string canonical_dex_file_location_;
- const uint32_t dex_file_location_checksum_;
- const uint8_t* const dex_file_pointer_;
- const uint8_t* lookup_table_data_;
- const uint32_t* const oat_class_offsets_pointer_;
- uint8_t* const dex_cache_arrays_;
+ const uint32_t dex_file_location_checksum_ = 0u;
+ const uint8_t* const dex_file_pointer_ = nullptr;
+ const uint8_t* lookup_table_data_ = nullptr;
+ const uint32_t* const oat_class_offsets_pointer_ = 0u;
+ uint8_t* const dex_cache_arrays_ = nullptr;
mutable std::unique_ptr<TypeLookupTable> lookup_table_;
friend class OatFile;
diff --git a/runtime/oat_file_assistant.cc b/runtime/oat_file_assistant.cc
index 0679360..4d1e1ea 100644
--- a/runtime/oat_file_assistant.cc
+++ b/runtime/oat_file_assistant.cc
@@ -16,6 +16,8 @@
#include "oat_file_assistant.h"
+#include <sstream>
+
#include <sys/stat.h>
#include "base/logging.h"
#include "base/stringprintf.h"
@@ -34,15 +36,21 @@
std::ostream& operator << (std::ostream& stream, const OatFileAssistant::OatStatus status) {
switch (status) {
- case OatFileAssistant::kOatOutOfDate:
- stream << "kOatOutOfDate";
+ case OatFileAssistant::kOatCannotOpen:
+ stream << "kOatCannotOpen";
+ break;
+ case OatFileAssistant::kOatDexOutOfDate:
+ stream << "kOatDexOutOfDate";
+ break;
+ case OatFileAssistant::kOatBootImageOutOfDate:
+ stream << "kOatBootImageOutOfDate";
+ break;
+ case OatFileAssistant::kOatRelocationOutOfDate:
+ stream << "kOatRelocationOutOfDate";
break;
case OatFileAssistant::kOatUpToDate:
stream << "kOatUpToDate";
break;
- case OatFileAssistant::kOatNeedsRelocation:
- stream << "kOatNeedsRelocation";
- break;
default:
UNREACHABLE();
}
@@ -60,7 +68,10 @@
const char* oat_location,
const InstructionSet isa,
bool load_executable)
- : isa_(isa), load_executable_(load_executable), odex_(this), oat_(this) {
+ : isa_(isa),
+ load_executable_(load_executable),
+ odex_(this, /*is_oat_location*/ false),
+ oat_(this, /*is_oat_location*/ true) {
CHECK(dex_location != nullptr) << "OatFileAssistant: null dex location";
dex_location_.assign(dex_location);
@@ -135,51 +146,13 @@
return true;
}
-OatFileAssistant::DexOptNeeded
-OatFileAssistant::GetDexOptNeeded(CompilerFilter::Filter target, bool profile_changed) {
- bool compilation_desired = CompilerFilter::IsBytecodeCompilationEnabled(target);
-
- // See if the oat file is in good shape as is.
- bool oat_okay = oat_.CompilerFilterIsOkay(target, profile_changed);
- if (oat_okay) {
- if (compilation_desired) {
- if (oat_.IsUpToDate()) {
- return kNoDexOptNeeded;
- }
- } else {
- if (!oat_.IsOutOfDate()) {
- return kNoDexOptNeeded;
- }
- }
+int OatFileAssistant::GetDexOptNeeded(CompilerFilter::Filter target, bool profile_changed) {
+ OatFileInfo& info = GetBestInfo();
+ DexOptNeeded dexopt_needed = info.GetDexOptNeeded(target, profile_changed);
+ if (info.IsOatLocation() || dexopt_needed == kDex2OatFromScratch) {
+ return dexopt_needed;
}
-
- // See if the odex file is in good shape as is.
- bool odex_okay = odex_.CompilerFilterIsOkay(target, profile_changed);
- if (odex_okay) {
- if (compilation_desired) {
- if (odex_.IsUpToDate()) {
- return kNoDexOptNeeded;
- }
- } else {
- if (!odex_.IsOutOfDate()) {
- return kNoDexOptNeeded;
- }
- }
- }
-
- // See if we can get an up-to-date file by running patchoat.
- if (compilation_desired) {
- if (odex_okay && odex_.NeedsRelocation() && odex_.HasPatchInfo()) {
- return kPatchOatNeeded;
- }
-
- if (oat_okay && oat_.NeedsRelocation() && oat_.HasPatchInfo()) {
- return kSelfPatchOatNeeded;
- }
- }
-
- // We can only run dex2oat if there are original dex files.
- return HasOriginalDexFiles() ? kDex2OatNeeded : kNoDexOptNeeded;
+ return -dexopt_needed;
}
// Figure out the currently specified compile filter option in the runtime.
@@ -205,7 +178,7 @@
}
bool OatFileAssistant::IsUpToDate() {
- return OatFileIsUpToDate() || OdexFileIsUpToDate();
+ return GetBestInfo().Status() == kOatUpToDate;
}
OatFileAssistant::ResultOfAttemptToUpdate
@@ -215,59 +188,66 @@
return kUpdateNotAttempted;
}
- switch (GetDexOptNeeded(target, profile_changed)) {
- case kNoDexOptNeeded: return kUpdateSucceeded;
- case kDex2OatNeeded: return GenerateOatFile(error_msg);
- case kPatchOatNeeded: return RelocateOatFile(odex_.Filename(), error_msg);
- case kSelfPatchOatNeeded: return RelocateOatFile(oat_.Filename(), error_msg);
+ OatFileInfo& info = GetBestInfo();
+ switch (info.GetDexOptNeeded(target, profile_changed)) {
+ case kNoDexOptNeeded:
+ return kUpdateSucceeded;
+
+ // TODO: For now, don't bother with all the different ways we can call
+ // dex2oat to generate the oat file. Always generate the oat file as if it
+ // were kDex2OatFromScratch.
+ case kDex2OatFromScratch:
+ case kDex2OatForBootImage:
+ case kDex2OatForRelocation:
+ case kDex2OatForFilter:
+ return GenerateOatFile(error_msg);
+
+ case kPatchoatForRelocation: {
+ return RelocateOatFile(info.Filename(), error_msg);
+ }
}
UNREACHABLE();
}
std::unique_ptr<OatFile> OatFileAssistant::GetBestOatFile() {
- // The best oat files are, in descending order of bestness:
- // 1. Properly relocated files. These may be opened executable.
- // 2. Not out-of-date files that are already opened non-executable.
- // 3. Not out-of-date files that we must reopen non-executable.
+ return GetBestInfo().ReleaseFileForUse();
+}
- if (oat_.IsUpToDate()) {
- return oat_.ReleaseFile();
+std::string OatFileAssistant::GetStatusDump() {
+ std::ostringstream status;
+ bool oat_file_exists = false;
+ bool odex_file_exists = false;
+ if (oat_.Status() != kOatCannotOpen) {
+ // If we can open the file, neither Filename nor GetFile should return null.
+ CHECK(oat_.Filename() != nullptr);
+ CHECK(oat_.GetFile() != nullptr);
+
+ oat_file_exists = true;
+ status << *oat_.Filename() << " [compilation_filter=";
+ status << CompilerFilter::NameOfFilter(oat_.GetFile()->GetCompilerFilter());
+ status << ", status=" << oat_.Status();
}
- if (odex_.IsUpToDate()) {
- return odex_.ReleaseFile();
- }
+ if (odex_.Status() != kOatCannotOpen) {
+ // If we can open the file, neither Filename nor GetFile should return null.
+ CHECK(odex_.Filename() != nullptr);
+ CHECK(odex_.GetFile() != nullptr);
- VLOG(oat) << "Oat File Assistant: No relocated oat file found,"
- << " attempting to fall back to interpreting oat file instead.";
-
- if (!oat_.IsOutOfDate() && !oat_.IsExecutable()) {
- return oat_.ReleaseFile();
- }
-
- if (!odex_.IsOutOfDate() && !odex_.IsExecutable()) {
- return odex_.ReleaseFile();
- }
-
- if (!oat_.IsOutOfDate()) {
- load_executable_ = false;
- oat_.Reset();
- if (!oat_.IsOutOfDate()) {
- CHECK(!oat_.IsExecutable());
- return oat_.ReleaseFile();
+ odex_file_exists = true;
+ if (oat_file_exists) {
+ status << "] ";
}
+ status << *odex_.Filename() << " [compilation_filter=";
+ status << CompilerFilter::NameOfFilter(odex_.GetFile()->GetCompilerFilter());
+ status << ", status=" << odex_.Status();
}
- if (!odex_.IsOutOfDate()) {
- load_executable_ = false;
- odex_.Reset();
- if (!odex_.IsOutOfDate()) {
- CHECK(!odex_.IsExecutable());
- return odex_.ReleaseFile();
- }
+ if (!oat_file_exists && !odex_file_exists) {
+ status << "invalid[";
}
- return std::unique_ptr<OatFile>();
+ status << "]";
+ return status.str();
}
std::vector<std::unique_ptr<const DexFile>> OatFileAssistant::LoadDexFiles(
@@ -317,62 +297,14 @@
return has_original_dex_files_;
}
-const std::string* OatFileAssistant::OdexFileName() {
- return odex_.Filename();
-}
-
-bool OatFileAssistant::OdexFileExists() {
- return odex_.Exists();
-}
-
OatFileAssistant::OatStatus OatFileAssistant::OdexFileStatus() {
return odex_.Status();
}
-bool OatFileAssistant::OdexFileIsOutOfDate() {
- return odex_.IsOutOfDate();
-}
-
-bool OatFileAssistant::OdexFileNeedsRelocation() {
- return odex_.NeedsRelocation();
-}
-
-bool OatFileAssistant::OdexFileIsUpToDate() {
- return odex_.IsUpToDate();
-}
-
-CompilerFilter::Filter OatFileAssistant::OdexFileCompilerFilter() {
- return odex_.CompilerFilter();
-}
-
-const std::string* OatFileAssistant::OatFileName() {
- return oat_.Filename();
-}
-
-bool OatFileAssistant::OatFileExists() {
- return oat_.Exists();
-}
-
OatFileAssistant::OatStatus OatFileAssistant::OatFileStatus() {
return oat_.Status();
}
-bool OatFileAssistant::OatFileIsOutOfDate() {
- return oat_.IsOutOfDate();
-}
-
-bool OatFileAssistant::OatFileNeedsRelocation() {
- return oat_.NeedsRelocation();
-}
-
-bool OatFileAssistant::OatFileIsUpToDate() {
- return oat_.IsUpToDate();
-}
-
-CompilerFilter::Filter OatFileAssistant::OatFileCompilerFilter() {
- return oat_.CompilerFilter();
-}
-
OatFileAssistant::OatStatus OatFileAssistant::GivenOatFileStatus(const OatFile& file) {
// Verify the dex checksum.
// Note: GetOatDexFile will return null if the dex checksum doesn't match
@@ -383,7 +315,7 @@
dex_location_.c_str(), dex_checksum_pointer, &error_msg);
if (oat_dex_file == nullptr) {
VLOG(oat) << error_msg;
- return kOatOutOfDate;
+ return kOatDexOutOfDate;
}
// Verify the dex checksums for any secondary multidex files
@@ -406,7 +338,7 @@
<< secondary_dex_location
<< ". Expected: " << expected_secondary_checksum
<< ", Actual: " << actual_secondary_checksum;
- return kOatOutOfDate;
+ return kOatDexOutOfDate;
}
} else {
// If we can't get the checksum for the secondary location, we assume
@@ -425,7 +357,7 @@
VLOG(oat) << "No image for oat image checksum to match against.";
if (HasOriginalDexFiles()) {
- return kOatOutOfDate;
+ return kOatBootImageOutOfDate;
}
// If there is no original dex file to fall back to, grudgingly accept
@@ -439,7 +371,7 @@
} else if (file.GetOatHeader().GetImageFileLocationOatChecksum()
!= GetCombinedImageChecksum()) {
VLOG(oat) << "Oat image checksum does not match image checksum.";
- return kOatOutOfDate;
+ return kOatBootImageOutOfDate;
}
} else {
VLOG(oat) << "Image checksum test skipped for compiler filter " << current_compiler_filter;
@@ -450,7 +382,7 @@
const ImageInfo* image_info = GetImageInfo();
if (image_info == nullptr) {
VLOG(oat) << "No image to check oat relocation against.";
- return kOatNeedsRelocation;
+ return kOatRelocationOutOfDate;
}
// Verify the oat_data_begin recorded for the image in the oat file matches
@@ -462,7 +394,7 @@
": Oat file image oat_data_begin (" << oat_data_begin << ")"
<< " does not match actual image oat_data_begin ("
<< image_info->oat_data_begin << ")";
- return kOatNeedsRelocation;
+ return kOatRelocationOutOfDate;
}
// Verify the oat_patch_delta recorded for the image in the oat file matches
@@ -473,7 +405,7 @@
": Oat file image patch delta (" << oat_patch_delta << ")"
<< " does not match actual image patch delta ("
<< image_info->patch_delta << ")";
- return kOatNeedsRelocation;
+ return kOatRelocationOutOfDate;
}
} else {
// Oat files compiled in PIC mode do not require relocation.
@@ -841,6 +773,11 @@
return combined_image_checksum_;
}
+OatFileAssistant::OatFileInfo& OatFileAssistant::GetBestInfo() {
+ bool use_oat = oat_.IsUseable() || odex_.Status() == kOatCannotOpen;
+ return use_oat ? oat_ : odex_;
+}
+
std::unique_ptr<gc::space::ImageSpace> OatFileAssistant::OpenImageSpace(const OatFile* oat_file) {
DCHECK(oat_file != nullptr);
std::string art_file = ReplaceFileExtension(oat_file->GetLocation(), "art");
@@ -857,16 +794,29 @@
return ret;
}
-OatFileAssistant::OatFileInfo::OatFileInfo(OatFileAssistant* oat_file_assistant)
- : oat_file_assistant_(oat_file_assistant)
+OatFileAssistant::OatFileInfo::OatFileInfo(OatFileAssistant* oat_file_assistant,
+ bool is_oat_location)
+ : oat_file_assistant_(oat_file_assistant), is_oat_location_(is_oat_location)
{}
+bool OatFileAssistant::OatFileInfo::IsOatLocation() {
+ return is_oat_location_;
+}
+
const std::string* OatFileAssistant::OatFileInfo::Filename() {
return filename_provided_ ? &filename_ : nullptr;
}
-bool OatFileAssistant::OatFileInfo::Exists() {
- return GetFile() != nullptr;
+bool OatFileAssistant::OatFileInfo::IsUseable() {
+ switch (Status()) {
+ case kOatCannotOpen:
+ case kOatDexOutOfDate:
+ case kOatBootImageOutOfDate: return false;
+
+ case kOatRelocationOutOfDate:
+ case kOatUpToDate: return true;
+ }
+ UNREACHABLE();
}
OatFileAssistant::OatStatus OatFileAssistant::OatFileInfo::Status() {
@@ -874,7 +824,7 @@
status_attempted_ = true;
const OatFile* file = GetFile();
if (file == nullptr) {
- status_ = kOatOutOfDate;
+ status_ = kOatCannotOpen;
} else {
status_ = oat_file_assistant_->GivenOatFileStatus(*file);
VLOG(oat) << file->GetLocation() << " is " << status_
@@ -884,22 +834,46 @@
return status_;
}
-bool OatFileAssistant::OatFileInfo::IsOutOfDate() {
- return Status() == kOatOutOfDate;
-}
+OatFileAssistant::DexOptNeeded OatFileAssistant::OatFileInfo::GetDexOptNeeded(
+ CompilerFilter::Filter target, bool profile_changed) {
+ bool compilation_desired = CompilerFilter::IsBytecodeCompilationEnabled(target);
+ bool filter_okay = CompilerFilterIsOkay(target, profile_changed);
-bool OatFileAssistant::OatFileInfo::NeedsRelocation() {
- return Status() == kOatNeedsRelocation;
-}
+ if (filter_okay && Status() == kOatUpToDate) {
+ // The oat file is in good shape as is.
+ return kNoDexOptNeeded;
+ }
-bool OatFileAssistant::OatFileInfo::IsUpToDate() {
- return Status() == kOatUpToDate;
-}
+ if (filter_okay && !compilation_desired && Status() == kOatRelocationOutOfDate) {
+ // If no compilation is desired, then it doesn't matter if the oat
+ // file needs relocation. It's in good shape as is.
+ return kNoDexOptNeeded;
+ }
-CompilerFilter::Filter OatFileAssistant::OatFileInfo::CompilerFilter() {
- const OatFile* file = GetFile();
- CHECK(file != nullptr);
- return file->GetCompilerFilter();
+ if (filter_okay && Status() == kOatRelocationOutOfDate && HasPatchInfo()) {
+ return kPatchoatForRelocation;
+ }
+
+ if (oat_file_assistant_->HasOriginalDexFiles()) {
+ // Run dex2oat for relocation if we didn't have the patch info necessary
+ // to use patchoat.
+ if (filter_okay && Status() == kOatRelocationOutOfDate) {
+ return kDex2OatForRelocation;
+ }
+
+ if (IsUseable()) {
+ return kDex2OatForFilter;
+ }
+
+ if (Status() == kOatBootImageOutOfDate) {
+ return kDex2OatForBootImage;
+ }
+
+ return kDex2OatFromScratch;
+ }
+
+ // Otherwise there is nothing we can do, even if we want to.
+ return kNoDexOptNeeded;
}
const OatFile* OatFileAssistant::OatFileInfo::GetFile() {
@@ -967,5 +941,31 @@
return std::move(file_);
}
+std::unique_ptr<OatFile> OatFileAssistant::OatFileInfo::ReleaseFileForUse() {
+ if (Status() == kOatUpToDate) {
+ return ReleaseFile();
+ }
+
+ VLOG(oat) << "Oat File Assistant: No relocated oat file found,"
+ << " attempting to fall back to interpreting oat file instead.";
+
+ if (Status() == kOatRelocationOutOfDate && !IsExecutable()) {
+ return ReleaseFile();
+ }
+
+ if (Status() == kOatRelocationOutOfDate) {
+ // We are loading an oat file for runtime use that needs relocation.
+ // Reload the file non-executable to ensure that we interpret out of the
+ // dex code in the oat file rather than trying to execute the unrelocated
+ // compiled code.
+ oat_file_assistant_->load_executable_ = false;
+ Reset();
+ if (IsUseable()) {
+ CHECK(!IsExecutable());
+ return ReleaseFile();
+ }
+ }
+ return std::unique_ptr<OatFile>();
+}
} // namespace art
diff --git a/runtime/oat_file_assistant.h b/runtime/oat_file_assistant.h
index 3f018dc..bed1edc 100644
--- a/runtime/oat_file_assistant.h
+++ b/runtime/oat_file_assistant.h
@@ -48,41 +48,56 @@
class OatFileAssistant {
public:
enum DexOptNeeded {
- // kNoDexOptNeeded - The code for this dex location is up to date and can
- // be used as is.
+ // No dexopt should (or can) be done to update the apk/jar.
// Matches Java: dalvik.system.DexFile.NO_DEXOPT_NEEDED = 0
kNoDexOptNeeded = 0,
- // kDex2OatNeeded - In order to make the code for this dex location up to
- // date, dex2oat must be run on the dex file.
- // Matches Java: dalvik.system.DexFile.DEX2OAT_NEEDED = 1
- kDex2OatNeeded = 1,
+ // dex2oat should be run to update the apk/jar from scratch.
+ // Matches Java: dalvik.system.DexFile.DEX2OAT_FROM_SCRATCH = 1
+ kDex2OatFromScratch = 1,
- // kPatchOatNeeded - In order to make the code for this dex location up to
- // date, patchoat must be run on the odex file.
- // Matches Java: dalvik.system.DexFile.PATCHOAT_NEEDED = 2
- kPatchOatNeeded = 2,
+ // dex2oat should be run to update the apk/jar because the existing code
+ // is out of date with respect to the boot image.
+ // Matches Java: dalvik.system.DexFile.DEX2OAT_FOR_BOOT_IMAGE
+ kDex2OatForBootImage = 2,
- // kSelfPatchOatNeeded - In order to make the code for this dex location
- // up to date, patchoat must be run on the oat file.
- // Matches Java: dalvik.system.DexFile.SELF_PATCHOAT_NEEDED = 3
- kSelfPatchOatNeeded = 3,
+ // dex2oat should be run to update the apk/jar because the existing code
+ // is out of date with respect to the target compiler filter.
+ // Matches Java: dalvik.system.DexFile.DEX2OAT_FOR_FILTER
+ kDex2OatForFilter = 3,
+
+ // dex2oat should be run to update the apk/jar because the existing code
+ // is not relocated to match the boot image and does not have the
+ // necessary patch information to use patchoat.
+ // Matches Java: dalvik.system.DexFile.DEX2OAT_FOR_RELOCATION
+ kDex2OatForRelocation = 4,
+
+ // patchoat should be run to update the apk/jar.
+ // Matches Java: dalvik.system.DexFile.PATCHOAT_FOR_RELOCATION
+ kPatchoatForRelocation = 5,
};
enum OatStatus {
- // kOatOutOfDate - An oat file is said to be out of date if the file does
- // not exist, is out of date with respect to the dex file or boot image,
- // or does not meet the target compilation type.
- kOatOutOfDate,
+ // kOatCannotOpen - The oat file cannot be opened, because it does not
+ // exist, is unreadable, or otherwise corrupted.
+ kOatCannotOpen,
- // kOatNeedsRelocation - An oat file is said to need relocation if the
- // code is up to date, but not yet properly relocated for address space
- // layout randomization (ASLR). In this case, the oat file is neither
- // "out of date" nor "up to date".
- kOatNeedsRelocation,
+ // kOatDexOutOfDate - The oat file is out of date with respect to the dex file.
+ kOatDexOutOfDate,
- // kOatUpToDate - An oat file is said to be up to date if it is not out of
- // date and has been properly relocated for the purposes of ASLR.
+ // kOatBootImageOutOfDate - The oat file is up to date with respect to the
+ // dex file, but is out of date with respect to the boot image.
+ kOatBootImageOutOfDate,
+
+ // kOatRelocationOutOfDate - The oat file is up to date with respect to
+ // the dex file and boot image, but contains compiled code that has the
+ // wrong patch delta with respect to the boot image. Patchoat should be
+ // run on the oat file to update the patch delta of the compiled code to
+ // match the boot image.
+ kOatRelocationOutOfDate,
+
+ // kOatUpToDate - The oat file is completely up to date with respect to
+ // the dex file and boot image.
kOatUpToDate,
};
@@ -142,8 +157,10 @@
// dex location that is at least as good as an oat file generated with the
// given compiler filter. profile_changed should be true to indicate the
// profile has recently changed for this dex location.
- DexOptNeeded GetDexOptNeeded(CompilerFilter::Filter target_compiler_filter,
- bool profile_changed = false);
+ // Returns a positive status code if the status refers to the oat file in
+ // the oat location. Returns a negative status code if the status refers to
+ // the oat file in the odex location.
+ int GetDexOptNeeded(CompilerFilter::Filter target_compiler_filter, bool profile_changed = false);
// Returns true if there is up-to-date code for this dex location,
// irrespective of the compiler filter of the up-to-date code.
@@ -179,6 +196,10 @@
// the OatFileAssistant object.
std::unique_ptr<OatFile> GetBestOatFile();
+ // Returns a human readable description of the status of the code for the
+ // dex file. The returned description is for debugging purposes only.
+ std::string GetStatusDump();
+
// Open and returns an image space associated with the oat file.
static std::unique_ptr<gc::space::ImageSpace> OpenImageSpace(const OatFile* oat_file);
@@ -205,43 +226,16 @@
// really an oat file. The odex file will often, but not always, have a
// patch delta of 0 and need to be relocated before use for the purposes of
// ASLR. The odex file is treated as if it were read-only.
- // These methods return the location and status of the odex file for the dex
- // location.
- // Notes:
- // * OdexFileName may return null if the odex file name could not be
- // determined.
- const std::string* OdexFileName();
- bool OdexFileExists();
+ //
+ // Returns the status of the odex file for the dex location.
OatStatus OdexFileStatus();
- bool OdexFileIsOutOfDate();
- bool OdexFileNeedsRelocation();
- bool OdexFileIsUpToDate();
- // Must only be called if the associated odex file exists, i.e, if
- // |OdexFileExists() == true|.
- CompilerFilter::Filter OdexFileCompilerFilter();
// When the dex files is compiled on the target device, the oat file is the
// result. The oat file will have been relocated to some
// (possibly-out-of-date) offset for ASLR.
- // These methods return the location and status of the target oat file for
- // the dex location.
//
- // Notes:
- // * OatFileName may return null if the oat file name could not be
- // determined.
- const std::string* OatFileName();
- bool OatFileExists();
+ // Returns the status of the oat file for the dex location.
OatStatus OatFileStatus();
- bool OatFileIsOutOfDate();
- bool OatFileNeedsRelocation();
- bool OatFileIsUpToDate();
- // Must only be called if the associated oat file exists, i.e, if
- // |OatFileExists() == true|.
- CompilerFilter::Filter OatFileCompilerFilter();
-
- // Return the status for a given opened oat file with respect to the dex
- // location.
- OatStatus GivenOatFileStatus(const OatFile& file);
// Generates the oat file by relocation from the named input file.
// This does not check the current status before attempting to relocate the
@@ -311,29 +305,39 @@
// Initially the info is for no file in particular. It will treat the
// file as out of date until Reset is called with a real filename to use
// the cache for.
- explicit OatFileInfo(OatFileAssistant* oat_file_assistant);
+ // Pass true for is_oat_location if the information associated with this
+ // OatFileInfo is for the oat location, as opposed to the odex location.
+ OatFileInfo(OatFileAssistant* oat_file_assistant, bool is_oat_location);
+
+ bool IsOatLocation();
const std::string* Filename();
- bool Exists();
+
+ // Returns true if this oat file can be used for running code. The oat
+ // file can be used for running code as long as it is not out of date with
+ // respect to the dex code or boot image. An oat file that is out of date
+ // with respect to relocation is considered useable, because it's possible
+ // to interpret the dex code rather than run the unrelocated compiled
+ // code.
+ bool IsUseable();
+
+ // Returns the status of this oat file.
OatStatus Status();
- bool IsOutOfDate();
- bool NeedsRelocation();
- bool IsUpToDate();
- // Must only be called if the associated file exists, i.e, if
- // |Exists() == true|.
- CompilerFilter::Filter CompilerFilter();
+
+ // Return the DexOptNeeded value for this oat file with respect to the
+ // given target_compilation_filter.
+ // profile_changed should be true to indicate the profile has recently
+ // changed for this dex location.
+ // If patchoat is needed, this function will return the kPatchOatNeeded
+ // status, not the kSelfPatchOatNeeded status.
+ DexOptNeeded GetDexOptNeeded(CompilerFilter::Filter target_compiler_filter,
+ bool profile_changed);
// Returns the loaded file.
// Loads the file if needed. Returns null if the file failed to load.
// The caller shouldn't clean up or free the returned pointer.
const OatFile* GetFile();
- // Returns true if the compiler filter used to generate the file is at
- // least as good as the given target filter. profile_changed should be
- // true to indicate the profile has recently changed for this dex
- // location.
- bool CompilerFilterIsOkay(CompilerFilter::Filter target, bool profile_changed);
-
// Returns true if the file is opened executable.
bool IsExecutable();
@@ -348,6 +352,23 @@
// file with the given filename.
void Reset(const std::string& filename);
+ // Release the loaded oat file for runtime use.
+ // Returns null if the oat file hasn't been loaded or is out of date.
+ // Ensures the returned file is not loaded executable if it has unuseable
+ // compiled code.
+ //
+ // After this call, no other methods of the OatFileInfo should be
+ // called, because access to the loaded oat file has been taken away from
+ // the OatFileInfo object.
+ std::unique_ptr<OatFile> ReleaseFileForUse();
+
+ private:
+ // Returns true if the compiler filter used to generate the file is at
+ // least as good as the given target filter. profile_changed should be
+ // true to indicate the profile has recently changed for this dex
+ // location.
+ bool CompilerFilterIsOkay(CompilerFilter::Filter target, bool profile_changed);
+
// Release the loaded oat file.
// Returns null if the oat file hasn't been loaded.
//
@@ -356,8 +377,8 @@
// the OatFileInfo object.
std::unique_ptr<OatFile> ReleaseFile();
- private:
OatFileAssistant* oat_file_assistant_;
+ const bool is_oat_location_;
bool filename_provided_ = false;
std::string filename_;
@@ -374,6 +395,13 @@
bool file_released_ = false;
};
+ // Return info for the best oat file.
+ OatFileInfo& GetBestInfo();
+
+ // Return the status for a given opened oat file with respect to the dex
+ // location.
+ OatStatus GivenOatFileStatus(const OatFile& file);
+
// Returns the current image location.
// Returns an empty string if the image location could not be retrieved.
//
diff --git a/runtime/oat_file_assistant_test.cc b/runtime/oat_file_assistant_test.cc
index d4337b9..5730cf2 100644
--- a/runtime/oat_file_assistant_test.cc
+++ b/runtime/oat_file_assistant_test.cc
@@ -49,9 +49,9 @@
// Pre-Relocate the image to a known non-zero offset so we don't have to
// deal with the runtime randomly relocating the image by 0 and messing up
// the expected results of the tests.
- bool PreRelocateImage(std::string* error_msg) {
+ bool PreRelocateImage(const std::string& image_location, std::string* error_msg) {
std::string image;
- if (!GetCachedImageFile(&image, error_msg)) {
+ if (!GetCachedImageFile(image_location, &image, error_msg)) {
return false;
}
@@ -60,7 +60,7 @@
std::vector<std::string> argv;
argv.push_back(patchoat);
- argv.push_back("--input-image-location=" + GetImageLocation());
+ argv.push_back("--input-image-location=" + image_location);
argv.push_back("--output-image-file=" + image);
argv.push_back("--instruction-set=" + std::string(GetInstructionSetString(kRuntimeISA)));
argv.push_back("--base-offset-delta=0x00008000");
@@ -69,8 +69,8 @@
virtual void PreRuntimeCreate() {
std::string error_msg;
- ASSERT_TRUE(PreRelocateImage(&error_msg)) << error_msg;
-
+ ASSERT_TRUE(PreRelocateImage(GetImageLocation(), &error_msg)) << error_msg;
+ ASSERT_TRUE(PreRelocateImage(GetImageLocation2(), &error_msg)) << error_msg;
UnreserveImageSpace();
}
@@ -78,24 +78,32 @@
ReserveImageSpace();
}
- // Generate a non-PIC odex file for the purposes of test.
- // The generated odex file will be un-relocated.
- void GenerateOdexForTest(const std::string& dex_location,
- const std::string& odex_location,
- CompilerFilter::Filter filter,
- bool pic = false,
- bool with_patch_info = true) {
- // Temporarily redirect the dalvik cache so dex2oat doesn't find the
- // relocated image file.
+ // Generate an oat file for the purposes of test.
+ void GenerateOatForTest(const std::string& dex_location,
+ const std::string& oat_location,
+ CompilerFilter::Filter filter,
+ bool relocate,
+ bool pic,
+ bool with_patch_info,
+ bool with_alternate_image) {
std::string dalvik_cache = GetDalvikCache(GetInstructionSetString(kRuntimeISA));
std::string dalvik_cache_tmp = dalvik_cache + ".redirected";
- ASSERT_EQ(0, rename(dalvik_cache.c_str(), dalvik_cache_tmp.c_str())) << strerror(errno);
+
+ if (!relocate) {
+ // Temporarily redirect the dalvik cache so dex2oat doesn't find the
+ // relocated image file.
+ ASSERT_EQ(0, rename(dalvik_cache.c_str(), dalvik_cache_tmp.c_str())) << strerror(errno);
+ }
std::vector<std::string> args;
args.push_back("--dex-file=" + dex_location);
- args.push_back("--oat-file=" + odex_location);
+ args.push_back("--oat-file=" + oat_location);
args.push_back("--compiler-filter=" + CompilerFilter::NameOfFilter(filter));
args.push_back("--runtime-arg");
+
+ // Use -Xnorelocate regardless of the relocate argument.
+ // We control relocation by redirecting the dalvik cache when needed
+ // rather than use this flag.
args.push_back("-Xnorelocate");
if (pic) {
@@ -106,14 +114,22 @@
args.push_back("--include-patch-information");
}
+ std::string image_location = GetImageLocation();
+ if (with_alternate_image) {
+ args.push_back("--boot-image=" + GetImageLocation2());
+ }
+
std::string error_msg;
ASSERT_TRUE(OatFileAssistant::Dex2Oat(args, &error_msg)) << error_msg;
- ASSERT_EQ(0, rename(dalvik_cache_tmp.c_str(), dalvik_cache.c_str())) << strerror(errno);
- // Verify the odex file was generated as expected and really is
- // unrelocated.
- std::unique_ptr<OatFile> odex_file(OatFile::Open(odex_location.c_str(),
- odex_location.c_str(),
+ if (!relocate) {
+ // Restore the dalvik cache if needed.
+ ASSERT_EQ(0, rename(dalvik_cache_tmp.c_str(), dalvik_cache.c_str())) << strerror(errno);
+ }
+
+ // Verify the odex file was generated as expected.
+ std::unique_ptr<OatFile> odex_file(OatFile::Open(oat_location.c_str(),
+ oat_location.c_str(),
nullptr,
nullptr,
false,
@@ -125,24 +141,59 @@
EXPECT_EQ(with_patch_info, odex_file->HasPatchInfo());
EXPECT_EQ(filter, odex_file->GetCompilerFilter());
- if (CompilerFilter::IsBytecodeCompilationEnabled(filter)) {
- const std::vector<gc::space::ImageSpace*> image_spaces =
- Runtime::Current()->GetHeap()->GetBootImageSpaces();
- ASSERT_TRUE(!image_spaces.empty() && image_spaces[0] != nullptr);
- const ImageHeader& image_header = image_spaces[0]->GetImageHeader();
- const OatHeader& oat_header = odex_file->GetOatHeader();
- uint32_t combined_checksum = OatFileAssistant::CalculateCombinedImageChecksum();
- EXPECT_EQ(combined_checksum, oat_header.GetImageFileLocationOatChecksum());
- EXPECT_NE(reinterpret_cast<uintptr_t>(image_header.GetOatDataBegin()),
- oat_header.GetImageFileLocationOatDataBegin());
- EXPECT_NE(image_header.GetPatchDelta(), oat_header.GetImagePatchDelta());
+ std::unique_ptr<ImageHeader> image_header(
+ gc::space::ImageSpace::ReadImageHeader(image_location.c_str(),
+ kRuntimeISA,
+ &error_msg));
+ ASSERT_TRUE(image_header != nullptr) << error_msg;
+ const OatHeader& oat_header = odex_file->GetOatHeader();
+ uint32_t combined_checksum = OatFileAssistant::CalculateCombinedImageChecksum();
+
+ if (CompilerFilter::DependsOnImageChecksum(filter)) {
+ if (with_alternate_image) {
+ EXPECT_NE(combined_checksum, oat_header.GetImageFileLocationOatChecksum());
+ } else {
+ EXPECT_EQ(combined_checksum, oat_header.GetImageFileLocationOatChecksum());
+ }
}
+
+ if (CompilerFilter::IsBytecodeCompilationEnabled(filter)) {
+ if (relocate) {
+ EXPECT_EQ(reinterpret_cast<uintptr_t>(image_header->GetOatDataBegin()),
+ oat_header.GetImageFileLocationOatDataBegin());
+ EXPECT_EQ(image_header->GetPatchDelta(), oat_header.GetImagePatchDelta());
+ } else {
+ EXPECT_NE(reinterpret_cast<uintptr_t>(image_header->GetOatDataBegin()),
+ oat_header.GetImageFileLocationOatDataBegin());
+ EXPECT_NE(image_header->GetPatchDelta(), oat_header.GetImagePatchDelta());
+ }
+ }
+ }
+
+ // Generate a non-PIC odex file for the purposes of test.
+ // The generated odex file will be un-relocated.
+ void GenerateOdexForTest(const std::string& dex_location,
+ const std::string& odex_location,
+ CompilerFilter::Filter filter) {
+ GenerateOatForTest(dex_location,
+ odex_location,
+ filter,
+ /*relocate*/false,
+ /*pic*/false,
+ /*with_patch_info*/true,
+ /*with_alternate_image*/false);
}
void GeneratePicOdexForTest(const std::string& dex_location,
const std::string& odex_location,
CompilerFilter::Filter filter) {
- GenerateOdexForTest(dex_location, odex_location, filter, true, false);
+ GenerateOatForTest(dex_location,
+ odex_location,
+ filter,
+ /*relocate*/false,
+ /*pic*/true,
+ /*with_patch_info*/false,
+ /*with_alternate_image*/false);
}
// Generate a non-PIC odex file without patch information for the purposes
@@ -150,7 +201,43 @@
void GenerateNoPatchOdexForTest(const std::string& dex_location,
const std::string& odex_location,
CompilerFilter::Filter filter) {
- GenerateOdexForTest(dex_location, odex_location, filter, false, false);
+ GenerateOatForTest(dex_location,
+ odex_location,
+ filter,
+ /*relocate*/false,
+ /*pic*/false,
+ /*with_patch_info*/false,
+ /*with_alternate_image*/false);
+ }
+
+ // Generate an oat file in the oat location.
+ void GenerateOatForTest(const char* dex_location,
+ CompilerFilter::Filter filter,
+ bool relocate,
+ bool pic,
+ bool with_patch_info,
+ bool with_alternate_image) {
+ std::string oat_location;
+ std::string error_msg;
+ ASSERT_TRUE(OatFileAssistant::DexLocationToOatFilename(
+ dex_location, kRuntimeISA, &oat_location, &error_msg)) << error_msg;
+ GenerateOatForTest(dex_location,
+ oat_location,
+ filter,
+ relocate,
+ pic,
+ with_patch_info,
+ with_alternate_image);
+ }
+
+ // Generate a standard oat file in the oat location.
+ void GenerateOatForTest(const char* dex_location, CompilerFilter::Filter filter) {
+ GenerateOatForTest(dex_location,
+ filter,
+ /*relocate*/true,
+ /*pic*/false,
+ /*with_patch_info*/false,
+ /*with_alternate_image*/false);
}
private:
@@ -211,36 +298,6 @@
}
};
-// Generate an oat file for the purposes of test, as opposed to testing
-// generation of oat files.
-static void GenerateOatForTest(const char* dex_location, CompilerFilter::Filter filter) {
- // Use an oat file assistant to find the proper oat location.
- std::string oat_location;
- std::string error_msg;
- ASSERT_TRUE(OatFileAssistant::DexLocationToOatFilename(
- dex_location, kRuntimeISA, &oat_location, &error_msg)) << error_msg;
-
- std::vector<std::string> args;
- args.push_back("--dex-file=" + std::string(dex_location));
- args.push_back("--oat-file=" + oat_location);
- args.push_back("--compiler-filter=" + CompilerFilter::NameOfFilter(filter));
- args.push_back("--runtime-arg");
- args.push_back("-Xnorelocate");
- ASSERT_TRUE(OatFileAssistant::Dex2Oat(args, &error_msg)) << error_msg;
-
- // Verify the oat file was generated as expected.
- std::unique_ptr<OatFile> oat_file(OatFile::Open(oat_location.c_str(),
- oat_location.c_str(),
- nullptr,
- nullptr,
- false,
- /*low_4gb*/false,
- dex_location,
- &error_msg));
- ASSERT_TRUE(oat_file.get() != nullptr) << error_msg;
- EXPECT_EQ(filter, oat_file->GetCompilerFilter());
-}
-
// Case: We have a DEX file, but no OAT file for it.
// Expect: The status is kDex2OatNeeded.
TEST_F(OatFileAssistantTest, DexNoOat) {
@@ -249,26 +306,18 @@
OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
- EXPECT_EQ(OatFileAssistant::kDex2OatNeeded,
+ EXPECT_EQ(OatFileAssistant::kDex2OatFromScratch,
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kVerifyAtRuntime));
- EXPECT_EQ(OatFileAssistant::kDex2OatNeeded,
+ EXPECT_EQ(OatFileAssistant::kDex2OatFromScratch,
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kInterpretOnly));
- EXPECT_EQ(OatFileAssistant::kDex2OatNeeded,
+ EXPECT_EQ(OatFileAssistant::kDex2OatFromScratch,
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeedProfile));
- EXPECT_EQ(OatFileAssistant::kDex2OatNeeded,
+ EXPECT_EQ(OatFileAssistant::kDex2OatFromScratch,
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
- EXPECT_FALSE(oat_file_assistant.OdexFileExists());
- EXPECT_TRUE(oat_file_assistant.OdexFileIsOutOfDate());
- EXPECT_FALSE(oat_file_assistant.OdexFileNeedsRelocation());
- EXPECT_FALSE(oat_file_assistant.OdexFileIsUpToDate());
- EXPECT_EQ(OatFileAssistant::kOatOutOfDate, oat_file_assistant.OdexFileStatus());
- EXPECT_FALSE(oat_file_assistant.OatFileExists());
- EXPECT_TRUE(oat_file_assistant.OatFileIsOutOfDate());
- EXPECT_FALSE(oat_file_assistant.OatFileNeedsRelocation());
- EXPECT_FALSE(oat_file_assistant.OatFileIsUpToDate());
- EXPECT_EQ(OatFileAssistant::kOatOutOfDate, oat_file_assistant.OatFileStatus());
+ EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OdexFileStatus());
+ EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OatFileStatus());
EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles());
}
@@ -307,17 +356,11 @@
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kInterpretOnly));
EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kVerifyAtRuntime));
- EXPECT_EQ(OatFileAssistant::kDex2OatNeeded,
+ EXPECT_EQ(OatFileAssistant::kDex2OatForFilter,
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kEverything));
EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
- EXPECT_FALSE(oat_file_assistant.OdexFileExists());
- EXPECT_TRUE(oat_file_assistant.OdexFileIsOutOfDate());
- EXPECT_FALSE(oat_file_assistant.OdexFileIsUpToDate());
- EXPECT_TRUE(oat_file_assistant.OatFileExists());
- EXPECT_FALSE(oat_file_assistant.OatFileIsOutOfDate());
- EXPECT_FALSE(oat_file_assistant.OatFileNeedsRelocation());
- EXPECT_TRUE(oat_file_assistant.OatFileIsUpToDate());
+ EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OdexFileStatus());
EXPECT_EQ(OatFileAssistant::kOatUpToDate, oat_file_assistant.OatFileStatus());
EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles());
}
@@ -337,17 +380,12 @@
OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
- EXPECT_EQ(OatFileAssistant::kDex2OatNeeded,
+ EXPECT_EQ(OatFileAssistant::kDex2OatFromScratch,
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
- EXPECT_TRUE(oat_file_assistant.OdexFileExists());
- EXPECT_TRUE(oat_file_assistant.OdexFileIsOutOfDate());
- EXPECT_FALSE(oat_file_assistant.OdexFileIsUpToDate());
- EXPECT_FALSE(oat_file_assistant.OatFileExists());
- EXPECT_TRUE(oat_file_assistant.OatFileIsOutOfDate());
- EXPECT_FALSE(oat_file_assistant.OatFileNeedsRelocation());
- EXPECT_FALSE(oat_file_assistant.OatFileIsUpToDate());
+ EXPECT_EQ(OatFileAssistant::kOatDexOutOfDate, oat_file_assistant.OdexFileStatus());
+ EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OatFileStatus());
}
// Case: We have a DEX file and speed-profile OAT file for it.
@@ -364,19 +402,13 @@
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeedProfile, false));
EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kInterpretOnly, false));
- EXPECT_EQ(OatFileAssistant::kDex2OatNeeded,
+ EXPECT_EQ(OatFileAssistant::kDex2OatForFilter,
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeedProfile, true));
- EXPECT_EQ(OatFileAssistant::kDex2OatNeeded,
+ EXPECT_EQ(OatFileAssistant::kDex2OatForFilter,
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kInterpretOnly, true));
EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
- EXPECT_FALSE(oat_file_assistant.OdexFileExists());
- EXPECT_TRUE(oat_file_assistant.OdexFileIsOutOfDate());
- EXPECT_FALSE(oat_file_assistant.OdexFileIsUpToDate());
- EXPECT_TRUE(oat_file_assistant.OatFileExists());
- EXPECT_FALSE(oat_file_assistant.OatFileIsOutOfDate());
- EXPECT_FALSE(oat_file_assistant.OatFileNeedsRelocation());
- EXPECT_TRUE(oat_file_assistant.OatFileIsUpToDate());
+ EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OdexFileStatus());
EXPECT_EQ(OatFileAssistant::kOatUpToDate, oat_file_assistant.OatFileStatus());
EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles());
}
@@ -416,7 +448,7 @@
Copy(GetMultiDexSrc2(), dex_location);
OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
- EXPECT_EQ(OatFileAssistant::kDex2OatNeeded,
+ EXPECT_EQ(OatFileAssistant::kDex2OatFromScratch,
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed, false));
EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles());
}
@@ -453,10 +485,10 @@
EXPECT_EQ(2u, dex_files.size());
}
-// Case: We have a DEX file and out-of-date OAT file.
-// Expect: The status is kDex2OatNeeded.
-TEST_F(OatFileAssistantTest, OatOutOfDate) {
- std::string dex_location = GetScratchDir() + "/OatOutOfDate.jar";
+// Case: We have a DEX file and an OAT file out of date with respect to the
+// dex checksum.
+TEST_F(OatFileAssistantTest, OatDexOutOfDate) {
+ std::string dex_location = GetScratchDir() + "/OatDexOutOfDate.jar";
// We create a dex, generate an oat for it, then overwrite the dex with a
// different dex to make the oat out of date.
@@ -465,18 +497,68 @@
Copy(GetDexSrc2(), dex_location);
OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
- EXPECT_EQ(OatFileAssistant::kDex2OatNeeded,
+ EXPECT_EQ(OatFileAssistant::kDex2OatFromScratch,
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kVerifyAtRuntime));
- EXPECT_EQ(OatFileAssistant::kDex2OatNeeded,
+ EXPECT_EQ(OatFileAssistant::kDex2OatFromScratch,
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
- EXPECT_FALSE(oat_file_assistant.OdexFileExists());
- EXPECT_TRUE(oat_file_assistant.OdexFileIsOutOfDate());
- EXPECT_FALSE(oat_file_assistant.OdexFileIsUpToDate());
- EXPECT_TRUE(oat_file_assistant.OatFileExists());
- EXPECT_TRUE(oat_file_assistant.OatFileIsOutOfDate());
- EXPECT_FALSE(oat_file_assistant.OatFileIsUpToDate());
+ EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OdexFileStatus());
+ EXPECT_EQ(OatFileAssistant::kOatDexOutOfDate, oat_file_assistant.OatFileStatus());
+ EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles());
+}
+
+// Case: We have a DEX file and an OAT file out of date with respect to the
+// boot image.
+TEST_F(OatFileAssistantTest, OatImageOutOfDate) {
+ std::string dex_location = GetScratchDir() + "/OatImageOutOfDate.jar";
+
+ Copy(GetDexSrc1(), dex_location);
+ GenerateOatForTest(dex_location.c_str(),
+ CompilerFilter::kSpeed,
+ /*relocate*/true,
+ /*pic*/false,
+ /*with_patch_info*/false,
+ /*with_alternate_image*/true);
+
+ OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
+ EXPECT_EQ(OatFileAssistant::kDex2OatForBootImage,
+ oat_file_assistant.GetDexOptNeeded(CompilerFilter::kVerifyAtRuntime));
+ EXPECT_EQ(OatFileAssistant::kDex2OatForBootImage,
+ oat_file_assistant.GetDexOptNeeded(CompilerFilter::kInterpretOnly));
+ EXPECT_EQ(OatFileAssistant::kDex2OatForBootImage,
+ oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
+
+ EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
+ EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OdexFileStatus());
+ EXPECT_EQ(OatFileAssistant::kOatBootImageOutOfDate, oat_file_assistant.OatFileStatus());
+ EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles());
+}
+
+// Case: We have a DEX file and a verify-at-runtime OAT file out of date with
+// respect to the boot image.
+// It shouldn't matter that the OAT file is out of date, because it is
+// verify-at-runtime.
+TEST_F(OatFileAssistantTest, OatVerifyAtRuntimeImageOutOfDate) {
+ std::string dex_location = GetScratchDir() + "/OatVerifyAtRuntimeImageOutOfDate.jar";
+
+ Copy(GetDexSrc1(), dex_location);
+ GenerateOatForTest(dex_location.c_str(),
+ CompilerFilter::kVerifyAtRuntime,
+ /*relocate*/true,
+ /*pic*/false,
+ /*with_patch_info*/false,
+ /*with_alternate_image*/true);
+
+ OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
+ EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
+ oat_file_assistant.GetDexOptNeeded(CompilerFilter::kVerifyAtRuntime));
+ EXPECT_EQ(OatFileAssistant::kDex2OatForFilter,
+ oat_file_assistant.GetDexOptNeeded(CompilerFilter::kInterpretOnly));
+
+ EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
+ EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OdexFileStatus());
+ EXPECT_EQ(OatFileAssistant::kOatUpToDate, oat_file_assistant.OatFileStatus());
EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles());
}
@@ -495,17 +577,12 @@
EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kVerifyAtRuntime));
- EXPECT_EQ(OatFileAssistant::kPatchOatNeeded,
+ EXPECT_EQ(-OatFileAssistant::kPatchoatForRelocation,
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
- EXPECT_TRUE(oat_file_assistant.OdexFileExists());
- EXPECT_FALSE(oat_file_assistant.OdexFileIsOutOfDate());
- EXPECT_FALSE(oat_file_assistant.OdexFileIsUpToDate());
- EXPECT_TRUE(oat_file_assistant.OdexFileNeedsRelocation());
- EXPECT_FALSE(oat_file_assistant.OatFileExists());
- EXPECT_TRUE(oat_file_assistant.OatFileIsOutOfDate());
- EXPECT_FALSE(oat_file_assistant.OatFileIsUpToDate());
+ EXPECT_EQ(OatFileAssistant::kOatRelocationOutOfDate, oat_file_assistant.OdexFileStatus());
+ EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OatFileStatus());
EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles());
// We should still be able to get the non-executable odex file to run from.
@@ -529,16 +606,12 @@
// Verify the status.
OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
- EXPECT_EQ(OatFileAssistant::kPatchOatNeeded,
+ EXPECT_EQ(-OatFileAssistant::kPatchoatForRelocation,
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
- EXPECT_TRUE(oat_file_assistant.OdexFileExists());
- EXPECT_FALSE(oat_file_assistant.OdexFileIsOutOfDate());
- EXPECT_FALSE(oat_file_assistant.OdexFileIsUpToDate());
- EXPECT_FALSE(oat_file_assistant.OatFileExists());
- EXPECT_TRUE(oat_file_assistant.OatFileIsOutOfDate());
- EXPECT_FALSE(oat_file_assistant.OatFileIsUpToDate());
+ EXPECT_EQ(OatFileAssistant::kOatRelocationOutOfDate, oat_file_assistant.OdexFileStatus());
+ EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OatFileStatus());
EXPECT_FALSE(oat_file_assistant.HasOriginalDexFiles());
// Make the oat file up to date.
@@ -551,12 +624,8 @@
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
- EXPECT_TRUE(oat_file_assistant.OdexFileExists());
- EXPECT_FALSE(oat_file_assistant.OdexFileIsOutOfDate());
- EXPECT_FALSE(oat_file_assistant.OdexFileIsUpToDate());
- EXPECT_TRUE(oat_file_assistant.OatFileExists());
- EXPECT_FALSE(oat_file_assistant.OatFileIsOutOfDate());
- EXPECT_TRUE(oat_file_assistant.OatFileIsUpToDate());
+ EXPECT_EQ(OatFileAssistant::kOatRelocationOutOfDate, oat_file_assistant.OdexFileStatus());
+ EXPECT_EQ(OatFileAssistant::kOatUpToDate, oat_file_assistant.OatFileStatus());
EXPECT_FALSE(oat_file_assistant.HasOriginalDexFiles());
// Verify we can load the dex files from it.
@@ -590,19 +659,14 @@
EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kVerifyAtRuntime));
- EXPECT_EQ(OatFileAssistant::kPatchOatNeeded,
+ EXPECT_EQ(-OatFileAssistant::kPatchoatForRelocation,
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded, // Can't run dex2oat because dex file is stripped.
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kEverything));
EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
- EXPECT_TRUE(oat_file_assistant.OdexFileExists());
- EXPECT_FALSE(oat_file_assistant.OdexFileIsOutOfDate());
- EXPECT_TRUE(oat_file_assistant.OdexFileNeedsRelocation());
- EXPECT_FALSE(oat_file_assistant.OdexFileIsUpToDate());
- EXPECT_TRUE(oat_file_assistant.OatFileExists());
- EXPECT_TRUE(oat_file_assistant.OatFileIsOutOfDate());
- EXPECT_FALSE(oat_file_assistant.OatFileIsUpToDate());
+ EXPECT_EQ(OatFileAssistant::kOatRelocationOutOfDate, oat_file_assistant.OdexFileStatus());
+ EXPECT_EQ(OatFileAssistant::kOatDexOutOfDate, oat_file_assistant.OatFileStatus());
EXPECT_FALSE(oat_file_assistant.HasOriginalDexFiles());
// Make the oat file up to date.
@@ -617,14 +681,8 @@
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kEverything));
EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
- EXPECT_TRUE(oat_file_assistant.OdexFileExists());
- EXPECT_FALSE(oat_file_assistant.OdexFileIsOutOfDate());
- EXPECT_TRUE(oat_file_assistant.OdexFileNeedsRelocation());
- EXPECT_FALSE(oat_file_assistant.OdexFileIsUpToDate());
- EXPECT_TRUE(oat_file_assistant.OatFileExists());
- EXPECT_FALSE(oat_file_assistant.OatFileIsOutOfDate());
- EXPECT_FALSE(oat_file_assistant.OatFileNeedsRelocation());
- EXPECT_TRUE(oat_file_assistant.OatFileIsUpToDate());
+ EXPECT_EQ(OatFileAssistant::kOatRelocationOutOfDate, oat_file_assistant.OdexFileStatus());
+ EXPECT_EQ(OatFileAssistant::kOatUpToDate, oat_file_assistant.OatFileStatus());
EXPECT_FALSE(oat_file_assistant.HasOriginalDexFiles());
// Verify we can load the dex files from it.
@@ -654,13 +712,8 @@
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kInterpretOnly));
EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
- EXPECT_FALSE(oat_file_assistant.OdexFileExists());
- EXPECT_TRUE(oat_file_assistant.OdexFileIsOutOfDate());
- EXPECT_FALSE(oat_file_assistant.OdexFileNeedsRelocation());
- EXPECT_FALSE(oat_file_assistant.OdexFileIsUpToDate());
- EXPECT_FALSE(oat_file_assistant.OatFileExists());
- EXPECT_TRUE(oat_file_assistant.OatFileIsOutOfDate());
- EXPECT_FALSE(oat_file_assistant.OatFileIsUpToDate());
+ EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OdexFileStatus());
+ EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OatFileStatus());
EXPECT_FALSE(oat_file_assistant.HasOriginalDexFiles());
// Make the oat file up to date. This should have no effect.
@@ -673,13 +726,8 @@
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
- EXPECT_FALSE(oat_file_assistant.OdexFileExists());
- EXPECT_TRUE(oat_file_assistant.OdexFileIsOutOfDate());
- EXPECT_FALSE(oat_file_assistant.OdexFileNeedsRelocation());
- EXPECT_FALSE(oat_file_assistant.OdexFileIsUpToDate());
- EXPECT_FALSE(oat_file_assistant.OatFileExists());
- EXPECT_TRUE(oat_file_assistant.OatFileIsOutOfDate());
- EXPECT_FALSE(oat_file_assistant.OatFileIsUpToDate());
+ EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OdexFileStatus());
+ EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OatFileStatus());
EXPECT_FALSE(oat_file_assistant.HasOriginalDexFiles());
}
@@ -699,20 +747,14 @@
EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kInterpretOnly));
- EXPECT_EQ(OatFileAssistant::kSelfPatchOatNeeded,
+ EXPECT_EQ(OatFileAssistant::kPatchoatForRelocation,
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
- EXPECT_EQ(OatFileAssistant::kDex2OatNeeded,
+ EXPECT_EQ(OatFileAssistant::kDex2OatForFilter,
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kEverything));
EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
- EXPECT_FALSE(oat_file_assistant.OdexFileExists());
- EXPECT_TRUE(oat_file_assistant.OdexFileIsOutOfDate());
- EXPECT_FALSE(oat_file_assistant.OdexFileNeedsRelocation());
- EXPECT_FALSE(oat_file_assistant.OdexFileIsUpToDate());
- EXPECT_TRUE(oat_file_assistant.OatFileExists());
- EXPECT_TRUE(oat_file_assistant.OatFileNeedsRelocation());
- EXPECT_FALSE(oat_file_assistant.OatFileIsOutOfDate());
- EXPECT_FALSE(oat_file_assistant.OatFileIsUpToDate());
+ EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OdexFileStatus());
+ EXPECT_EQ(OatFileAssistant::kOatRelocationOutOfDate, oat_file_assistant.OatFileStatus());
EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles());
// Make the oat file up to date.
@@ -725,14 +767,8 @@
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
- EXPECT_FALSE(oat_file_assistant.OdexFileExists());
- EXPECT_TRUE(oat_file_assistant.OdexFileIsOutOfDate());
- EXPECT_FALSE(oat_file_assistant.OdexFileNeedsRelocation());
- EXPECT_FALSE(oat_file_assistant.OdexFileIsUpToDate());
- EXPECT_TRUE(oat_file_assistant.OatFileExists());
- EXPECT_FALSE(oat_file_assistant.OatFileIsOutOfDate());
- EXPECT_FALSE(oat_file_assistant.OatFileNeedsRelocation());
- EXPECT_TRUE(oat_file_assistant.OatFileIsUpToDate());
+ EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OdexFileStatus());
+ EXPECT_EQ(OatFileAssistant::kOatUpToDate, oat_file_assistant.OatFileStatus());
EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles());
std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
@@ -757,7 +793,7 @@
OatFileAssistant oat_file_assistant(dex_location.c_str(),
oat_location.c_str(), kRuntimeISA, true);
- EXPECT_EQ(OatFileAssistant::kDex2OatNeeded,
+ EXPECT_EQ(OatFileAssistant::kDex2OatForRelocation,
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
// Make the oat file up to date.
@@ -778,7 +814,7 @@
// Case: We have a DEX file, an ODEX file and an OAT file, where the ODEX and
// OAT files both have patch delta of 0.
-// Expect: It shouldn't crash, and status is kPatchOatNeeded.
+// Expect: It shouldn't crash, and status is kSelfPatchOatNeeded.
TEST_F(OatFileAssistantTest, OdexOatOverlap) {
std::string dex_location = GetScratchDir() + "/OdexOatOverlap.jar";
std::string odex_location = GetOdexDir() + "/OdexOatOverlap.odex";
@@ -796,16 +832,15 @@
OatFileAssistant oat_file_assistant(dex_location.c_str(),
oat_location.c_str(), kRuntimeISA, true);
- EXPECT_EQ(OatFileAssistant::kPatchOatNeeded,
+ // kPatchoatForRelocation is expected rather than -kPatchoatForRelocation
+ // based on the assumption that the oat location is more up-to-date than the odex
+ // location, even if they both need relocation.
+ EXPECT_EQ(OatFileAssistant::kPatchoatForRelocation,
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
- EXPECT_TRUE(oat_file_assistant.OdexFileExists());
- EXPECT_FALSE(oat_file_assistant.OdexFileIsOutOfDate());
- EXPECT_FALSE(oat_file_assistant.OdexFileIsUpToDate());
- EXPECT_TRUE(oat_file_assistant.OatFileExists());
- EXPECT_FALSE(oat_file_assistant.OatFileIsOutOfDate());
- EXPECT_FALSE(oat_file_assistant.OatFileIsUpToDate());
+ EXPECT_EQ(OatFileAssistant::kOatRelocationOutOfDate, oat_file_assistant.OdexFileStatus());
+ EXPECT_EQ(OatFileAssistant::kOatRelocationOutOfDate, oat_file_assistant.OatFileStatus());
EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles());
// Things aren't relocated, so it should fall back to interpreted.
@@ -833,16 +868,12 @@
EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
- EXPECT_EQ(OatFileAssistant::kDex2OatNeeded,
+ EXPECT_EQ(-OatFileAssistant::kDex2OatForFilter,
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kEverything));
EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
- EXPECT_TRUE(oat_file_assistant.OdexFileExists());
- EXPECT_FALSE(oat_file_assistant.OdexFileIsOutOfDate());
- EXPECT_TRUE(oat_file_assistant.OdexFileIsUpToDate());
- EXPECT_FALSE(oat_file_assistant.OatFileExists());
- EXPECT_TRUE(oat_file_assistant.OatFileIsOutOfDate());
- EXPECT_FALSE(oat_file_assistant.OatFileIsUpToDate());
+ EXPECT_EQ(OatFileAssistant::kOatUpToDate, oat_file_assistant.OdexFileStatus());
+ EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OatFileStatus());
EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles());
}
@@ -861,16 +892,12 @@
EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kVerifyAtRuntime));
- EXPECT_EQ(OatFileAssistant::kDex2OatNeeded,
+ EXPECT_EQ(-OatFileAssistant::kDex2OatForFilter,
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
- EXPECT_TRUE(oat_file_assistant.OdexFileExists());
- EXPECT_FALSE(oat_file_assistant.OdexFileIsOutOfDate());
- EXPECT_TRUE(oat_file_assistant.OdexFileIsUpToDate());
- EXPECT_FALSE(oat_file_assistant.OatFileExists());
- EXPECT_TRUE(oat_file_assistant.OatFileIsOutOfDate());
- EXPECT_FALSE(oat_file_assistant.OatFileIsUpToDate());
+ EXPECT_EQ(OatFileAssistant::kOatUpToDate, oat_file_assistant.OdexFileStatus());
+ EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OatFileStatus());
EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles());
}
@@ -958,7 +985,7 @@
// Verify it didn't create an oat in the default location.
OatFileAssistant ofm(dex_location.c_str(), kRuntimeISA, false);
- EXPECT_FALSE(ofm.OatFileExists());
+ EXPECT_EQ(OatFileAssistant::kOatCannotOpen, ofm.OatFileStatus());
}
// Case: We have a DEX file but can't write the oat file.
@@ -1043,14 +1070,10 @@
OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
- EXPECT_EQ(OatFileAssistant::kDex2OatNeeded,
+ EXPECT_EQ(OatFileAssistant::kDex2OatFromScratch,
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
- EXPECT_FALSE(oat_file_assistant.OdexFileExists());
- EXPECT_FALSE(oat_file_assistant.OatFileExists());
- EXPECT_TRUE(oat_file_assistant.OdexFileIsOutOfDate());
- EXPECT_FALSE(oat_file_assistant.OdexFileIsUpToDate());
- EXPECT_TRUE(oat_file_assistant.OatFileIsOutOfDate());
- EXPECT_FALSE(oat_file_assistant.OatFileIsUpToDate());
+ EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OdexFileStatus());
+ EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OatFileStatus());
}
// Case: Very short, non-existent Dex location.
@@ -1063,12 +1086,8 @@
EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
- EXPECT_FALSE(oat_file_assistant.OdexFileExists());
- EXPECT_FALSE(oat_file_assistant.OatFileExists());
- EXPECT_TRUE(oat_file_assistant.OdexFileIsOutOfDate());
- EXPECT_FALSE(oat_file_assistant.OdexFileIsUpToDate());
- EXPECT_TRUE(oat_file_assistant.OatFileIsOutOfDate());
- EXPECT_FALSE(oat_file_assistant.OatFileIsUpToDate());
+ EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OdexFileStatus());
+ EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OatFileStatus());
EXPECT_FALSE(oat_file_assistant.HasOriginalDexFiles());
// Trying to make it up to date should have no effect.
@@ -1087,16 +1106,12 @@
OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
- EXPECT_EQ(OatFileAssistant::kDex2OatNeeded,
+ EXPECT_EQ(OatFileAssistant::kDex2OatFromScratch,
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
- EXPECT_FALSE(oat_file_assistant.OdexFileExists());
- EXPECT_TRUE(oat_file_assistant.OdexFileIsOutOfDate());
- EXPECT_FALSE(oat_file_assistant.OdexFileIsUpToDate());
- EXPECT_FALSE(oat_file_assistant.OatFileExists());
- EXPECT_TRUE(oat_file_assistant.OatFileIsOutOfDate());
- EXPECT_FALSE(oat_file_assistant.OatFileIsUpToDate());
+ EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OdexFileStatus());
+ EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OatFileStatus());
}
// A task to generate a dex location. Used by the RaceToGenerate test.
@@ -1226,7 +1241,7 @@
oat_file_assistant.MakeUpToDate(false, &error_msg)) << error_msg;
EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kInterpretOnly));
- EXPECT_EQ(OatFileAssistant::kDex2OatNeeded,
+ EXPECT_EQ(OatFileAssistant::kDex2OatForFilter,
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
Runtime::Current()->AddCompilerOption("--compiler-filter=speed");
@@ -1263,6 +1278,15 @@
// Verify the dexopt status values from dalvik.system.DexFile
// match the OatFileAssistant::DexOptStatus values.
TEST_F(OatFileAssistantTest, DexOptStatusValues) {
+ std::pair<OatFileAssistant::DexOptNeeded, const char*> mapping[] = {
+ {OatFileAssistant::kNoDexOptNeeded, "NO_DEXOPT_NEEDED"},
+ {OatFileAssistant::kDex2OatFromScratch, "DEX2OAT_FROM_SCRATCH"},
+ {OatFileAssistant::kDex2OatForBootImage, "DEX2OAT_FOR_BOOT_IMAGE"},
+ {OatFileAssistant::kDex2OatForFilter, "DEX2OAT_FOR_FILTER"},
+ {OatFileAssistant::kDex2OatForRelocation, "DEX2OAT_FOR_RELOCATION"},
+ {OatFileAssistant::kPatchoatForRelocation, "PATCHOAT_FOR_RELOCATION"}
+ };
+
ScopedObjectAccess soa(Thread::Current());
StackHandleScope<1> hs(soa.Self());
ClassLinker* linker = Runtime::Current()->GetClassLinker();
@@ -1271,35 +1295,16 @@
ASSERT_FALSE(dexfile.Get() == nullptr);
linker->EnsureInitialized(soa.Self(), dexfile, true, true);
- ArtField* no_dexopt_needed = mirror::Class::FindStaticField(
- soa.Self(), dexfile, "NO_DEXOPT_NEEDED", "I");
- ASSERT_FALSE(no_dexopt_needed == nullptr);
- EXPECT_EQ(no_dexopt_needed->GetTypeAsPrimitiveType(), Primitive::kPrimInt);
- EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded, no_dexopt_needed->GetInt(dexfile.Get()));
-
- ArtField* dex2oat_needed = mirror::Class::FindStaticField(
- soa.Self(), dexfile, "DEX2OAT_NEEDED", "I");
- ASSERT_FALSE(dex2oat_needed == nullptr);
- EXPECT_EQ(dex2oat_needed->GetTypeAsPrimitiveType(), Primitive::kPrimInt);
- EXPECT_EQ(OatFileAssistant::kDex2OatNeeded, dex2oat_needed->GetInt(dexfile.Get()));
-
- ArtField* patchoat_needed = mirror::Class::FindStaticField(
- soa.Self(), dexfile, "PATCHOAT_NEEDED", "I");
- ASSERT_FALSE(patchoat_needed == nullptr);
- EXPECT_EQ(patchoat_needed->GetTypeAsPrimitiveType(), Primitive::kPrimInt);
- EXPECT_EQ(OatFileAssistant::kPatchOatNeeded, patchoat_needed->GetInt(dexfile.Get()));
-
- ArtField* self_patchoat_needed = mirror::Class::FindStaticField(
- soa.Self(), dexfile, "SELF_PATCHOAT_NEEDED", "I");
- ASSERT_FALSE(self_patchoat_needed == nullptr);
- EXPECT_EQ(self_patchoat_needed->GetTypeAsPrimitiveType(), Primitive::kPrimInt);
- EXPECT_EQ(OatFileAssistant::kSelfPatchOatNeeded, self_patchoat_needed->GetInt(dexfile.Get()));
+ for (std::pair<OatFileAssistant::DexOptNeeded, const char*> field : mapping) {
+ ArtField* art_field = mirror::Class::FindStaticField(
+ soa.Self(), dexfile, field.second, "I");
+ ASSERT_FALSE(art_field == nullptr);
+ EXPECT_EQ(art_field->GetTypeAsPrimitiveType(), Primitive::kPrimInt);
+ EXPECT_EQ(field.first, art_field->GetInt(dexfile.Get()));
+ }
}
// TODO: More Tests:
-// * Image checksum change is out of date for kIntepretOnly, but not
-// kVerifyAtRuntime. But target of kVerifyAtRuntime still says current
-// kInterpretOnly is out of date.
// * Test class linker falls back to unquickened dex for DexNoOat
// * Test class linker falls back to unquickened dex for MultiDexNoOat
// * Test using secondary isa
@@ -1313,5 +1318,4 @@
// because it's unrelocated and no dex2oat
// * Test unrelocated specific target compilation type can be relocated to
// make it up to date.
-
} // namespace art
diff --git a/runtime/oat_quick_method_header.h b/runtime/oat_quick_method_header.h
index ee5002f..4afca7d 100644
--- a/runtime/oat_quick_method_header.h
+++ b/runtime/oat_quick_method_header.h
@@ -67,6 +67,11 @@
return data;
}
+ uint8_t* GetOptimizedCodeInfoPtr() {
+ DCHECK(IsOptimized());
+ return code_ - vmap_table_offset_;
+ }
+
CodeInfo GetOptimizedCodeInfo() const {
return CodeInfo(GetOptimizedCodeInfoPtr());
}
diff --git a/runtime/openjdkjvmti/ti_heap.cc b/runtime/openjdkjvmti/ti_heap.cc
index 0eff469..5e588a8 100644
--- a/runtime/openjdkjvmti/ti_heap.cc
+++ b/runtime/openjdkjvmti/ti_heap.cc
@@ -269,6 +269,12 @@
ReportRoot(root_obj, info);
}
+ // Remove NO_THREAD_SAFETY_ANALYSIS once ASSERT_CAPABILITY works correctly.
+ art::Thread* FindThread(const art::RootInfo& info) NO_THREAD_SAFETY_ANALYSIS {
+ art::Locks::thread_list_lock_->AssertExclusiveHeld(art::Thread::Current());
+ return art::Runtime::Current()->GetThreadList()->FindThreadByThreadId(info.GetThreadId());
+ }
+
jvmtiHeapReferenceKind GetReferenceKind(const art::RootInfo& info,
jvmtiHeapReferenceInfo* ref_info)
REQUIRES_SHARED(art::Locks::mutator_lock_) {
@@ -280,7 +286,34 @@
return JVMTI_HEAP_REFERENCE_JNI_GLOBAL;
case art::RootType::kRootJNILocal:
+ {
+ uint32_t thread_id = info.GetThreadId();
+ ref_info->jni_local.thread_id = thread_id;
+
+ art::Thread* thread = FindThread(info);
+ if (thread != nullptr) {
+ art::mirror::Object* thread_obj = thread->GetPeer();
+ if (thread->IsStillStarting()) {
+ thread_obj = nullptr;
+ } else {
+ thread_obj = thread->GetPeer();
+ }
+ if (thread_obj != nullptr) {
+ ref_info->jni_local.thread_tag = tag_table_->GetTagOrZero(thread_obj);
+ }
+ }
+
+ // TODO: We don't have this info.
+ if (thread != nullptr) {
+ ref_info->jni_local.depth = 0;
+ art::ArtMethod* method = thread->GetCurrentMethod(nullptr, false /* abort_on_error */);
+ if (method != nullptr) {
+ ref_info->jni_local.method = art::jni::EncodeArtMethod(method);
+ }
+ }
+
return JVMTI_HEAP_REFERENCE_JNI_LOCAL;
+ }
case art::RootType::kRootJavaFrame:
return JVMTI_HEAP_REFERENCE_STACK_LOCAL;
diff --git a/runtime/openjdkjvmti/ti_method.cc b/runtime/openjdkjvmti/ti_method.cc
index e391a9d..ffa5ac7 100644
--- a/runtime/openjdkjvmti/ti_method.cc
+++ b/runtime/openjdkjvmti/ti_method.cc
@@ -78,7 +78,9 @@
}
// TODO: Support generic signature.
- *generic_ptr = nullptr;
+ if (generic_ptr != nullptr) {
+ *generic_ptr = nullptr;
+ }
// Everything is fine, release the buffers.
name_copy.release();
diff --git a/runtime/openjdkjvmti/transform.cc b/runtime/openjdkjvmti/transform.cc
index fa2983c..7bb5205 100644
--- a/runtime/openjdkjvmti/transform.cc
+++ b/runtime/openjdkjvmti/transform.cc
@@ -33,6 +33,7 @@
#include "class_linker.h"
#include "dex_file.h"
+#include "dex_file_types.h"
#include "gc_root-inl.h"
#include "globals.h"
#include "jni_env_ext-inl.h"
@@ -108,10 +109,10 @@
// Find the code_item for the method then find the dex_method_index and dex_code_item_offset to
// set.
const art::DexFile::StringId* new_name_id = dex_file->FindStringId(method.GetName());
- uint16_t method_return_idx =
+ art::dex::TypeIndex method_return_idx =
dex_file->GetIndexForTypeId(*dex_file->FindTypeId(method.GetReturnTypeDescriptor()));
const auto* old_type_list = method.GetParameterTypeList();
- std::vector<uint16_t> new_type_list;
+ std::vector<art::dex::TypeIndex> new_type_list;
for (uint32_t i = 0; old_type_list != nullptr && i < old_type_list->Size(); i++) {
new_type_list.push_back(
dex_file->GetIndexForTypeId(
diff --git a/runtime/reflection.cc b/runtime/reflection.cc
index 3128380..8446b52 100644
--- a/runtime/reflection.cc
+++ b/runtime/reflection.cc
@@ -363,7 +363,7 @@
Thread* const self = Thread::Current();
PointerSize pointer_size = Runtime::Current()->GetClassLinker()->GetImagePointerSize();
for (uint32_t i = 0; i < num_params; i++) {
- uint16_t type_idx = params->GetTypeItem(i).type_idx_;
+ dex::TypeIndex type_idx = params->GetTypeItem(i).type_idx_;
ObjPtr<mirror::Class> param_type(m->GetClassFromTypeIndex(type_idx,
true /* resolve*/,
pointer_size));
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 6177ef9..ee4d669 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -81,6 +81,7 @@
#include "intern_table.h"
#include "interpreter/interpreter.h"
#include "jit/jit.h"
+#include "jit/jit_code_cache.h"
#include "jni_internal.h"
#include "linear_alloc.h"
#include "mirror/array.h"
@@ -372,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++;
@@ -428,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) {
@@ -442,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.
@@ -492,6 +517,14 @@
GetMonitorList()->SweepMonitorList(visitor);
GetJavaVM()->SweepJniWeakGlobals(visitor);
GetHeap()->SweepAllocationRecords(visitor);
+ if (GetJit() != nullptr) {
+ // Visit JIT literal tables. Objects in these tables are classes and strings
+ // and only classes can be affected by class unloading. The strings always
+ // stay alive as they are strongly interned.
+ // TODO: Move this closer to CleanupClassLoaders, to avoid blocking weak accesses
+ // from mutators. See b/32167580.
+ GetJit()->GetCodeCache()->SweepRootTables(visitor);
+ }
// All other generic system-weak holders.
for (gc::AbstractSystemWeakHolder* holder : system_weak_holders_) {
@@ -1029,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),
@@ -2148,7 +2183,7 @@
NO_RETURN
void Runtime::Aborter(const char* abort_message) {
-#ifdef __ANDROID__
+#ifdef ART_TARGET_ANDROID
android_set_abort_message(abort_message);
#endif
Runtime::Abort(abort_message);
diff --git a/runtime/thread.cc b/runtime/thread.cc
index debd13a..c92e38b 100644
--- a/runtime/thread.cc
+++ b/runtime/thread.cc
@@ -1906,7 +1906,7 @@
}
delete tlsPtr_.instrumentation_stack;
delete tlsPtr_.name;
- delete tlsPtr_.stack_trace_sample;
+ delete tlsPtr_.deps_or_stack_trace_sample.stack_trace_sample;
free(tlsPtr_.nested_signal_state);
Runtime::Current()->GetHeap()->AssertThreadLocalBuffersAreRevoked(this);
diff --git a/runtime/thread.h b/runtime/thread.h
index 2079646..35226f2 100644
--- a/runtime/thread.h
+++ b/runtime/thread.h
@@ -39,6 +39,7 @@
#include "jvalue.h"
#include "object_callbacks.h"
#include "offsets.h"
+#include "runtime.h"
#include "runtime_stats.h"
#include "stack.h"
#include "thread_state.h"
@@ -70,7 +71,8 @@
} // namespace mirror
namespace verifier {
-class MethodVerifier;
+ class MethodVerifier;
+ class VerifierDeps;
} // namespace verifier
class ArtMethod;
@@ -947,11 +949,27 @@
}
std::vector<ArtMethod*>* GetStackTraceSample() const {
- return tlsPtr_.stack_trace_sample;
+ DCHECK(!Runtime::Current()->IsAotCompiler());
+ return tlsPtr_.deps_or_stack_trace_sample.stack_trace_sample;
}
void SetStackTraceSample(std::vector<ArtMethod*>* sample) {
- tlsPtr_.stack_trace_sample = sample;
+ DCHECK(!Runtime::Current()->IsAotCompiler());
+ tlsPtr_.deps_or_stack_trace_sample.stack_trace_sample = sample;
+ }
+
+ verifier::VerifierDeps* GetVerifierDeps() const {
+ DCHECK(Runtime::Current()->IsAotCompiler());
+ return tlsPtr_.deps_or_stack_trace_sample.verifier_deps;
+ }
+
+ // It is the responsability of the caller to make sure the verifier_deps
+ // entry in the thread is cleared before destruction of the actual VerifierDeps
+ // object, or the thread.
+ void SetVerifierDeps(verifier::VerifierDeps* verifier_deps) {
+ DCHECK(Runtime::Current()->IsAotCompiler());
+ DCHECK(verifier_deps == nullptr || tlsPtr_.deps_or_stack_trace_sample.verifier_deps == nullptr);
+ tlsPtr_.deps_or_stack_trace_sample.verifier_deps = verifier_deps;
}
uint64_t GetTraceClockBase() const {
@@ -1378,7 +1396,7 @@
tls_ptr_sized_values() : card_table(nullptr), exception(nullptr), stack_end(nullptr),
managed_stack(), suspend_trigger(nullptr), jni_env(nullptr), tmp_jni_env(nullptr),
self(nullptr), opeer(nullptr), jpeer(nullptr), stack_begin(nullptr), stack_size(0),
- stack_trace_sample(nullptr), wait_next(nullptr), monitor_enter_object(nullptr),
+ deps_or_stack_trace_sample(), wait_next(nullptr), monitor_enter_object(nullptr),
top_handle_scope(nullptr), class_loader_override(nullptr), long_jump_context(nullptr),
instrumentation_stack(nullptr), debug_invoke_req(nullptr), single_step_control(nullptr),
stacked_shadow_frame_record(nullptr), deoptimization_context_stack(nullptr),
@@ -1432,8 +1450,18 @@
// Size of the stack.
size_t stack_size;
- // Pointer to previous stack trace captured by sampling profiler.
- std::vector<ArtMethod*>* stack_trace_sample;
+ // Sampling profiler and AOT verification cannot happen on the same run, so we share
+ // the same entry for the stack trace and the verifier deps.
+ union DepsOrStackTraceSample {
+ DepsOrStackTraceSample() {
+ verifier_deps = nullptr;
+ stack_trace_sample = nullptr;
+ }
+ // Pointer to previous stack trace captured by sampling profiler.
+ std::vector<ArtMethod*>* stack_trace_sample;
+ // When doing AOT verification, per-thread VerifierDeps.
+ verifier::VerifierDeps* verifier_deps;
+ } deps_or_stack_trace_sample;
// The next thread in the wait set this thread is part of or null if not waiting.
Thread* wait_next;
diff --git a/runtime/thread_pool.cc b/runtime/thread_pool.cc
index b14f340..d9d2ea3 100644
--- a/runtime/thread_pool.cc
+++ b/runtime/thread_pool.cc
@@ -85,6 +85,7 @@
ThreadPoolWorker* worker = reinterpret_cast<ThreadPoolWorker*>(arg);
Runtime* runtime = Runtime::Current();
CHECK(runtime->AttachCurrentThread(worker->name_.c_str(), true, nullptr, false));
+ worker->thread_ = Thread::Current();
// Do work until its time to shut down.
worker->Run();
runtime->DetachCurrentThread();
@@ -177,7 +178,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 +201,7 @@
}
Task* ThreadPool::TryGetTaskLocked() {
- if (started_ && !tasks_.empty()) {
+ if (HasOutstandingTasks()) {
Task* task = tasks_.front();
tasks_.pop_front();
return task;
@@ -218,7 +219,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..eaadfe0 100644
--- a/runtime/thread_pool.h
+++ b/runtime/thread_pool.h
@@ -62,6 +62,8 @@
// Set the "nice" priorty for this worker.
void SetPthreadPriority(int priority);
+ Thread* GetThread() const { return thread_; }
+
protected:
ThreadPoolWorker(ThreadPool* thread_pool, const std::string& name, size_t stack_size);
static void* Callback(void* arg) REQUIRES(!Locks::mutator_lock_);
@@ -71,6 +73,7 @@
const std::string name_;
std::unique_ptr<MemMap> stack_;
pthread_t pthread_;
+ Thread* thread_;
private:
friend class ThreadPool;
@@ -84,6 +87,10 @@
return threads_.size();
}
+ const std::vector<ThreadPoolWorker*>& GetWorkers() const {
+ return threads_;
+ }
+
// Broadcast to the workers and tell them to empty out the work queue.
void StartWorkers(Thread* self) REQUIRES(!task_queue_lock_);
@@ -100,7 +107,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 +138,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/type_lookup_table.cc b/runtime/type_lookup_table.cc
index 56e9262..16cd722 100644
--- a/runtime/type_lookup_table.cc
+++ b/runtime/type_lookup_table.cc
@@ -50,17 +50,19 @@
return num_class_defs != 0u && num_class_defs <= std::numeric_limits<uint16_t>::max();
}
-TypeLookupTable* TypeLookupTable::Create(const DexFile& dex_file, uint8_t* storage) {
+std::unique_ptr<TypeLookupTable> TypeLookupTable::Create(const DexFile& dex_file,
+ uint8_t* storage) {
const uint32_t num_class_defs = dex_file.NumClassDefs();
- return SupportedSize(num_class_defs)
+ return std::unique_ptr<TypeLookupTable>(SupportedSize(num_class_defs)
? new TypeLookupTable(dex_file, storage)
- : nullptr;
+ : nullptr);
}
-TypeLookupTable* TypeLookupTable::Open(const uint8_t* dex_file_pointer,
- const uint8_t* raw_data,
- uint32_t num_class_defs) {
- return new TypeLookupTable(dex_file_pointer, raw_data, num_class_defs);
+std::unique_ptr<TypeLookupTable> TypeLookupTable::Open(const uint8_t* dex_file_pointer,
+ const uint8_t* raw_data,
+ uint32_t num_class_defs) {
+ return std::unique_ptr<TypeLookupTable>(
+ new TypeLookupTable(dex_file_pointer, raw_data, num_class_defs));
}
TypeLookupTable::TypeLookupTable(const DexFile& dex_file, uint8_t* storage)
diff --git a/runtime/type_lookup_table.h b/runtime/type_lookup_table.h
index 9595743..3f6f76f 100644
--- a/runtime/type_lookup_table.h
+++ b/runtime/type_lookup_table.h
@@ -60,13 +60,14 @@
}
// Method creates lookup table for dex file
- static TypeLookupTable* Create(const DexFile& dex_file, uint8_t* storage = nullptr);
+ static std::unique_ptr<TypeLookupTable> Create(const DexFile& dex_file,
+ uint8_t* storage = nullptr);
// Method opens lookup table from binary data. Lookups will traverse strings and other
// data contained in dex_file as well. Lookup table does not own raw_data or dex_file.
- static TypeLookupTable* Open(const uint8_t* dex_file_pointer,
- const uint8_t* raw_data,
- uint32_t num_class_defs);
+ static std::unique_ptr<TypeLookupTable> Open(const uint8_t* dex_file_pointer,
+ const uint8_t* raw_data,
+ uint32_t num_class_defs);
// Method returns pointer to binary data of lookup table. Used by the oat writer.
const uint8_t* RawData() const {
diff --git a/runtime/utils/dex_cache_arrays_layout-inl.h b/runtime/utils/dex_cache_arrays_layout-inl.h
index c7875b5..bd1b044 100644
--- a/runtime/utils/dex_cache_arrays_layout-inl.h
+++ b/runtime/utils/dex_cache_arrays_layout-inl.h
@@ -65,8 +65,8 @@
return PointerSize::k32;
}
-inline size_t DexCacheArraysLayout::TypeOffset(uint32_t type_idx) const {
- return types_offset_ + ElementOffset(GcRootAsPointerSize<mirror::Class>(), type_idx);
+inline size_t DexCacheArraysLayout::TypeOffset(dex::TypeIndex type_idx) const {
+ return types_offset_ + ElementOffset(GcRootAsPointerSize<mirror::Class>(), type_idx.index_);
}
inline size_t DexCacheArraysLayout::TypesSize(size_t num_elements) const {
diff --git a/runtime/utils/dex_cache_arrays_layout.h b/runtime/utils/dex_cache_arrays_layout.h
index ae3bfab..7d4b23a 100644
--- a/runtime/utils/dex_cache_arrays_layout.h
+++ b/runtime/utils/dex_cache_arrays_layout.h
@@ -18,6 +18,7 @@
#define ART_RUNTIME_UTILS_DEX_CACHE_ARRAYS_LAYOUT_H_
#include "dex_file.h"
+#include "dex_file_types.h"
namespace art {
@@ -59,7 +60,7 @@
return types_offset_;
}
- size_t TypeOffset(uint32_t type_idx) const;
+ size_t TypeOffset(dex::TypeIndex type_idx) const;
size_t TypesSize(size_t num_elements) const;
diff --git a/runtime/vdex_file.cc b/runtime/vdex_file.cc
index b3dab58..843be92 100644
--- a/runtime/vdex_file.cc
+++ b/runtime/vdex_file.cc
@@ -20,6 +20,7 @@
#include "base/logging.h"
#include "base/unix_file/fd_file.h"
+#include "dex_file.h"
namespace art {
@@ -73,10 +74,19 @@
return nullptr;
}
+ return Open(vdex_file->Fd(), vdex_length, vdex_filename, writable, low_4gb, error_msg);
+}
+
+VdexFile* VdexFile::Open(int file_fd,
+ size_t vdex_length,
+ const std::string& vdex_filename,
+ bool writable,
+ bool low_4gb,
+ std::string* error_msg) {
std::unique_ptr<MemMap> mmap(MemMap::MapFile(vdex_length,
writable ? PROT_READ | PROT_WRITE : PROT_READ,
MAP_SHARED,
- vdex_file->Fd(),
+ file_fd,
0 /* start offset */,
low_4gb,
vdex_filename.c_str(),
@@ -90,4 +100,16 @@
return new VdexFile(mmap.release());
}
+const uint8_t* VdexFile::GetNextDexFileData(const uint8_t* cursor) const {
+ DCHECK(cursor == nullptr || (cursor > Begin() && cursor <= End()));
+ if (cursor == nullptr) {
+ // Beginning of the iteration, return the first dex file if there is one.
+ return HasDexSection() ? DexBegin() : nullptr;
+ } else {
+ // Fetch the next dex file. Return null if there is none.
+ const uint8_t* data = cursor + reinterpret_cast<const DexFile::Header*>(cursor)->file_size_;
+ return (data == DexEnd()) ? nullptr : data;
+ }
+}
+
} // namespace art
diff --git a/runtime/vdex_file.h b/runtime/vdex_file.h
index edd6ffe..75a0d5e 100644
--- a/runtime/vdex_file.h
+++ b/runtime/vdex_file.h
@@ -71,6 +71,13 @@
bool low_4gb,
std::string* error_msg);
+ static VdexFile* Open(int file_fd,
+ size_t vdex_length,
+ const std::string& vdex_filename,
+ bool writable,
+ bool low_4gb,
+ std::string* error_msg);
+
const uint8_t* Begin() const { return mmap_->Begin(); }
const uint8_t* End() const { return mmap_->End(); }
size_t Size() const { return mmap_->Size(); }
@@ -84,9 +91,37 @@
Begin() + sizeof(Header) + GetHeader().GetDexSize(), GetHeader().GetVerifierDepsSize());
}
+ ArrayRef<const uint8_t> GetQuickeningInfo() const {
+ return ArrayRef<const uint8_t>(
+ GetVerifierDepsData().data() + GetHeader().GetVerifierDepsSize(),
+ GetHeader().GetQuickeningInfoSize());
+ }
+
+ bool IsValid() const {
+ return mmap_->Size() >= sizeof(Header) && GetHeader().IsValid();
+ }
+
+ // This method is for iterating over the dex files in the vdex. If `cursor` is null,
+ // the first dex file is returned. If `cursor` is not null, it must point to a dex
+ // file and this method returns the next dex file if there is one, or null if there
+ // is none.
+ const uint8_t* GetNextDexFileData(const uint8_t* cursor) const;
+
private:
explicit VdexFile(MemMap* mmap) : mmap_(mmap) {}
+ bool HasDexSection() const {
+ return GetHeader().GetDexSize() != 0;
+ }
+
+ const uint8_t* DexBegin() const {
+ return Begin() + sizeof(Header);
+ }
+
+ const uint8_t* DexEnd() const {
+ return Begin() + sizeof(Header) + GetHeader().GetDexSize();
+ }
+
std::unique_ptr<MemMap> mmap_;
DISALLOW_COPY_AND_ASSIGN(VdexFile);
diff --git a/runtime/verifier/method_verifier-inl.h b/runtime/verifier/method_verifier-inl.h
index def61db..363bd8f 100644
--- a/runtime/verifier/method_verifier-inl.h
+++ b/runtime/verifier/method_verifier-inl.h
@@ -74,7 +74,7 @@
return !failure_messages_.empty();
}
-inline const RegType& MethodVerifier::ResolveCheckedClass(uint32_t class_idx) {
+inline const RegType& MethodVerifier::ResolveCheckedClass(dex::TypeIndex class_idx) {
DCHECK(!HasFailures());
const RegType& result = ResolveClassAndCheckAccess(class_idx);
DCHECK(!HasFailures());
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index d9e3ea7..7137db8 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) {
@@ -1062,7 +1072,7 @@
GetInstructionFlags(dex_pc).SetBranchTarget();
// Ensure exception types are resolved so that they don't need resolution to be delivered,
// unresolved exception types will be ignored by exception delivery
- if (iterator.GetHandlerTypeIndex() != DexFile::kDexNoIndex16) {
+ if (iterator.GetHandlerTypeIndex().IsValid()) {
mirror::Class* exception_type = linker->ResolveType(*dex_file_,
iterator.GetHandlerTypeIndex(),
dex_cache_, class_loader_);
@@ -1145,13 +1155,13 @@
result = result && CheckMethodIndex(inst->VRegB());
break;
case Instruction::kVerifyRegBNewInstance:
- result = result && CheckNewInstance(inst->VRegB());
+ result = result && CheckNewInstance(dex::TypeIndex(inst->VRegB()));
break;
case Instruction::kVerifyRegBString:
result = result && CheckStringIndex(inst->VRegB());
break;
case Instruction::kVerifyRegBType:
- result = result && CheckTypeIndex(inst->VRegB());
+ result = result && CheckTypeIndex(dex::TypeIndex(inst->VRegB()));
break;
case Instruction::kVerifyRegBWide:
result = result && CheckWideRegisterIndex(inst->VRegB());
@@ -1165,10 +1175,10 @@
result = result && CheckFieldIndex(inst->VRegC());
break;
case Instruction::kVerifyRegCNewArray:
- result = result && CheckNewArray(inst->VRegC());
+ result = result && CheckNewArray(dex::TypeIndex(inst->VRegC()));
break;
case Instruction::kVerifyRegCType:
- result = result && CheckTypeIndex(inst->VRegC());
+ result = result && CheckTypeIndex(dex::TypeIndex(inst->VRegC()));
break;
case Instruction::kVerifyRegCWide:
result = result && CheckWideRegisterIndex(inst->VRegC());
@@ -1260,9 +1270,9 @@
return true;
}
-inline bool MethodVerifier::CheckNewInstance(uint32_t idx) {
- if (idx >= dex_file_->GetHeader().type_ids_size_) {
- Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "bad type index " << idx << " (max "
+inline bool MethodVerifier::CheckNewInstance(dex::TypeIndex idx) {
+ if (idx.index_ >= dex_file_->GetHeader().type_ids_size_) {
+ Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "bad type index " << idx.index_ << " (max "
<< dex_file_->GetHeader().type_ids_size_ << ")";
return false;
}
@@ -1288,18 +1298,18 @@
return true;
}
-inline bool MethodVerifier::CheckTypeIndex(uint32_t idx) {
- if (idx >= dex_file_->GetHeader().type_ids_size_) {
- Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "bad type index " << idx << " (max "
+inline bool MethodVerifier::CheckTypeIndex(dex::TypeIndex idx) {
+ if (idx.index_ >= dex_file_->GetHeader().type_ids_size_) {
+ Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "bad type index " << idx.index_ << " (max "
<< dex_file_->GetHeader().type_ids_size_ << ")";
return false;
}
return true;
}
-bool MethodVerifier::CheckNewArray(uint32_t idx) {
- if (idx >= dex_file_->GetHeader().type_ids_size_) {
- Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "bad type index " << idx << " (max "
+bool MethodVerifier::CheckNewArray(dex::TypeIndex idx) {
+ if (idx.index_ >= dex_file_->GetHeader().type_ids_size_) {
+ Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "bad type index " << idx.index_ << " (max "
<< dex_file_->GetHeader().type_ids_size_ << ")";
return false;
}
@@ -1935,7 +1945,7 @@
// Returns the index of the first final instance field of the given class, or kDexNoIndex if there
// is no such field.
-static uint32_t GetFirstFinalInstanceFieldIndex(const DexFile& dex_file, uint16_t type_idx) {
+static uint32_t GetFirstFinalInstanceFieldIndex(const DexFile& dex_file, dex::TypeIndex type_idx) {
const DexFile::ClassDef* class_def = dex_file.FindClassDef(type_idx);
DCHECK(class_def != nullptr);
const uint8_t* class_data = dex_file.GetClassData(*class_def);
@@ -2283,7 +2293,7 @@
case Instruction::CONST_CLASS: {
// Get type from instruction if unresolved then we need an access check
// TODO: check Compiler::CanAccessTypeWithoutChecks returns false when res_type is unresolved
- const RegType& res_type = ResolveClassAndCheckAccess(inst->VRegB_21c());
+ const RegType& res_type = ResolveClassAndCheckAccess(dex::TypeIndex(inst->VRegB_21c()));
// Register holds class, ie its type is class, on error it will hold Conflict.
work_line_->SetRegisterType<LockOp::kClear>(
this, inst->VRegA_21c(), res_type.IsConflict() ? res_type
@@ -2353,7 +2363,7 @@
* dec_insn.vA when branching to a handler.
*/
const bool is_checkcast = (inst->Opcode() == Instruction::CHECK_CAST);
- const uint32_t type_idx = (is_checkcast) ? inst->VRegB_21c() : inst->VRegC_22c();
+ const dex::TypeIndex type_idx((is_checkcast) ? inst->VRegB_21c() : inst->VRegC_22c());
const RegType& res_type = ResolveClassAndCheckAccess(type_idx);
if (res_type.IsConflict()) {
// If this is a primitive type, fail HARD.
@@ -2423,7 +2433,7 @@
break;
}
case Instruction::NEW_INSTANCE: {
- const RegType& res_type = ResolveClassAndCheckAccess(inst->VRegB_21c());
+ const RegType& res_type = ResolveClassAndCheckAccess(dex::TypeIndex(inst->VRegB_21c()));
if (res_type.IsConflict()) {
DCHECK_NE(failures_.size(), 0U);
break; // bad class
@@ -2635,7 +2645,8 @@
// ensure that subsequent merges don't lose type information - such as becoming an
// interface from a class that would lose information relevant to field checks.
const RegType& orig_type = work_line_->GetRegisterType(this, instance_of_inst->VRegB_22c());
- const RegType& cast_type = ResolveClassAndCheckAccess(instance_of_inst->VRegC_22c());
+ const RegType& cast_type = ResolveClassAndCheckAccess(
+ dex::TypeIndex(instance_of_inst->VRegC_22c()));
if (!orig_type.Equals(cast_type) &&
!cast_type.IsUnresolvedTypes() && !orig_type.IsUnresolvedTypes() &&
@@ -2873,7 +2884,8 @@
if (return_type == nullptr) {
uint32_t method_idx = (is_range) ? inst->VRegB_3rc() : inst->VRegB_35c();
const DexFile::MethodId& method_id = dex_file_->GetMethodId(method_idx);
- uint32_t return_type_idx = dex_file_->GetProtoId(method_id.proto_idx_).return_type_idx_;
+ dex::TypeIndex return_type_idx =
+ dex_file_->GetProtoId(method_id.proto_idx_).return_type_idx_;
const char* descriptor = dex_file_->StringByTypeIdx(return_type_idx);
return_type = ®_types_.FromDescriptor(GetClassLoader(), descriptor, false);
}
@@ -2896,7 +2908,8 @@
uint32_t method_idx = (is_range) ? inst->VRegB_3rc() : inst->VRegB_35c();
const DexFile::MethodId& method_id = dex_file_->GetMethodId(method_idx);
is_constructor = strcmp("<init>", dex_file_->StringDataByIdx(method_id.name_idx_)) == 0;
- uint32_t return_type_idx = dex_file_->GetProtoId(method_id.proto_idx_).return_type_idx_;
+ dex::TypeIndex return_type_idx =
+ dex_file_->GetProtoId(method_id.proto_idx_).return_type_idx_;
return_type_descriptor = dex_file_->StringByTypeIdx(return_type_idx);
} else {
is_constructor = called_method->IsConstructor();
@@ -2972,7 +2985,8 @@
if (called_method == nullptr) {
uint32_t method_idx = (is_range) ? inst->VRegB_3rc() : inst->VRegB_35c();
const DexFile::MethodId& method_id = dex_file_->GetMethodId(method_idx);
- uint32_t return_type_idx = dex_file_->GetProtoId(method_id.proto_idx_).return_type_idx_;
+ dex::TypeIndex return_type_idx =
+ dex_file_->GetProtoId(method_id.proto_idx_).return_type_idx_;
descriptor = dex_file_->StringByTypeIdx(return_type_idx);
} else {
descriptor = called_method->GetReturnTypeDescriptor();
@@ -3026,7 +3040,8 @@
if (abs_method == nullptr) {
uint32_t method_idx = (is_range) ? inst->VRegB_3rc() : inst->VRegB_35c();
const DexFile::MethodId& method_id = dex_file_->GetMethodId(method_idx);
- uint32_t return_type_idx = dex_file_->GetProtoId(method_id.proto_idx_).return_type_idx_;
+ dex::TypeIndex return_type_idx =
+ dex_file_->GetProtoId(method_id.proto_idx_).return_type_idx_;
descriptor = dex_file_->StringByTypeIdx(return_type_idx);
} else {
descriptor = abs_method->GetReturnTypeDescriptor();
@@ -3490,8 +3505,8 @@
ClassLinker* linker = Runtime::Current()->GetClassLinker();
for (; iterator.HasNext(); iterator.Next()) {
- uint16_t handler_type_idx = iterator.GetHandlerTypeIndex();
- if (handler_type_idx == DexFile::kDexNoIndex16) {
+ dex::TypeIndex handler_type_idx = iterator.GetHandlerTypeIndex();
+ if (!handler_type_idx.IsValid()) {
has_catch_all_handler = true;
} else {
// It is also a catch-all if it is java.lang.Throwable.
@@ -3618,7 +3633,7 @@
return klass->IsInstantiable() || klass->IsPrimitive();
}
-const RegType& MethodVerifier::ResolveClassAndCheckAccess(uint32_t class_idx) {
+const RegType& MethodVerifier::ResolveClassAndCheckAccess(dex::TypeIndex class_idx) {
mirror::Class* klass = dex_cache_->GetResolvedType(class_idx);
const RegType* result = nullptr;
if (klass != nullptr) {
@@ -3674,7 +3689,7 @@
CatchHandlerIterator iterator(handlers_ptr);
for (; iterator.HasNext(); iterator.Next()) {
if (iterator.GetHandlerAddress() == (uint32_t) work_insn_idx_) {
- if (iterator.GetHandlerTypeIndex() == DexFile::kDexNoIndex16) {
+ if (!iterator.GetHandlerTypeIndex().IsValid()) {
common_super = ®_types_.JavaLangThrowable(false);
} else {
const RegType& exception = ResolveClassAndCheckAccess(iterator.GetHandlerTypeIndex());
@@ -3931,7 +3946,7 @@
klass->CannotBeAssignedFromOtherTypes());
} else {
const uint32_t method_idx = (is_range) ? inst->VRegB_3rc() : inst->VRegB_35c();
- const uint16_t class_idx = dex_file_->GetMethodId(method_idx).class_idx_;
+ const dex::TypeIndex class_idx = dex_file_->GetMethodId(method_idx).class_idx_;
res_method_class = ®_types_.FromDescriptor(
GetClassLoader(),
dex_file_->StringByTypeIdx(class_idx),
@@ -4068,7 +4083,7 @@
// If we're using invoke-super(method), make sure that the executing method's class' superclass
// has a vtable entry for the target method. Or the target is on a interface.
if (method_type == METHOD_SUPER) {
- uint16_t class_idx = dex_file_->GetMethodId(method_idx).class_idx_;
+ dex::TypeIndex class_idx = dex_file_->GetMethodId(method_idx).class_idx_;
const RegType& reference_type = reg_types_.FromDescriptor(
GetClassLoader(),
dex_file_->StringByTypeIdx(class_idx),
@@ -4277,16 +4292,16 @@
}
void MethodVerifier::VerifyNewArray(const Instruction* inst, bool is_filled, bool is_range) {
- uint32_t type_idx;
+ dex::TypeIndex type_idx;
if (!is_filled) {
DCHECK_EQ(inst->Opcode(), Instruction::NEW_ARRAY);
- type_idx = inst->VRegC_22c();
+ type_idx = dex::TypeIndex(inst->VRegC_22c());
} else if (!is_range) {
DCHECK_EQ(inst->Opcode(), Instruction::FILLED_NEW_ARRAY);
- type_idx = inst->VRegB_35c();
+ type_idx = dex::TypeIndex(inst->VRegB_35c());
} else {
DCHECK_EQ(inst->Opcode(), Instruction::FILLED_NEW_ARRAY_RANGE);
- type_idx = inst->VRegB_3rc();
+ type_idx = dex::TypeIndex(inst->VRegB_3rc());
}
const RegType& res_type = ResolveClassAndCheckAccess(type_idx);
if (res_type.IsConflict()) { // bad class
@@ -5001,7 +5016,7 @@
if (return_type_ == nullptr) {
const DexFile::MethodId& method_id = dex_file_->GetMethodId(dex_method_idx_);
const DexFile::ProtoId& proto_id = dex_file_->GetMethodPrototype(method_id);
- uint16_t return_type_idx = proto_id.return_type_idx_;
+ dex::TypeIndex return_type_idx = proto_id.return_type_idx_;
const char* descriptor = dex_file_->GetTypeDescriptor(dex_file_->GetTypeId(return_type_idx));
return_type_ = ®_types_.FromDescriptor(GetClassLoader(), descriptor, false);
}
diff --git a/runtime/verifier/method_verifier.h b/runtime/verifier/method_verifier.h
index c6ce583..f3faecd 100644
--- a/runtime/verifier/method_verifier.h
+++ b/runtime/verifier/method_verifier.h
@@ -27,6 +27,7 @@
#include "base/stl_util.h"
#include "base/value_object.h"
#include "dex_file.h"
+#include "dex_file_types.h"
#include "handle.h"
#include "instruction_flags.h"
#include "method_reference.h"
@@ -261,7 +262,7 @@
return have_any_pending_runtime_throw_failure_;
}
- const RegType& ResolveCheckedClass(uint32_t class_idx)
+ const RegType& ResolveCheckedClass(dex::TypeIndex class_idx)
REQUIRES_SHARED(Locks::mutator_lock_);
// Returns the method of a quick invoke or null if it cannot be found.
ArtMethod* GetQuickInvokedMethod(const Instruction* inst, RegisterLine* reg_line,
@@ -471,18 +472,18 @@
// Perform static checks on a "new-instance" instruction. Specifically, make sure the class
// reference isn't for an array class.
- bool CheckNewInstance(uint32_t idx);
+ bool CheckNewInstance(dex::TypeIndex idx);
/* Ensure that the string index is in the valid range. */
bool CheckStringIndex(uint32_t idx);
// Perform static checks on an instruction that takes a class constant. Ensure that the class
// index is in the valid range.
- bool CheckTypeIndex(uint32_t idx);
+ bool CheckTypeIndex(dex::TypeIndex idx);
// Perform static checks on a "new-array" instruction. Specifically, make sure they aren't
// creating an array of arrays that causes the number of dimensions to exceed 255.
- bool CheckNewArray(uint32_t idx);
+ bool CheckNewArray(dex::TypeIndex idx);
// Verify an array data table. "cur_offset" is the offset of the fill-array-data instruction.
bool CheckArrayData(uint32_t cur_offset);
@@ -625,7 +626,7 @@
// Resolves a class based on an index and performs access checks to ensure the referrer can
// access the resolved class.
- const RegType& ResolveClassAndCheckAccess(uint32_t class_idx)
+ const RegType& ResolveClassAndCheckAccess(dex::TypeIndex class_idx)
REQUIRES_SHARED(Locks::mutator_lock_);
/*
diff --git a/runtime/verifier/verifier_deps.cc b/runtime/verifier/verifier_deps.cc
index c395612..01af5ec 100644
--- a/runtime/verifier/verifier_deps.cc
+++ b/runtime/verifier/verifier_deps.cc
@@ -16,6 +16,9 @@
#include "verifier_deps.h"
+#include <cstring>
+
+#include "base/stl_util.h"
#include "compiler_callbacks.h"
#include "leb128.h"
#include "mirror/class-inl.h"
@@ -26,7 +29,6 @@
namespace verifier {
VerifierDeps::VerifierDeps(const std::vector<const DexFile*>& dex_files) {
- MutexLock mu(Thread::Current(), *Locks::verifier_deps_lock_);
for (const DexFile* dex_file : dex_files) {
DCHECK(GetDexFileDeps(*dex_file) == nullptr);
std::unique_ptr<DexFileDeps> deps(new DexFileDeps());
@@ -34,6 +36,28 @@
}
}
+void VerifierDeps::MergeWith(const VerifierDeps& other,
+ const std::vector<const DexFile*>& dex_files) {
+ DCHECK(dex_deps_.size() == other.dex_deps_.size());
+ for (const DexFile* dex_file : dex_files) {
+ DexFileDeps* my_deps = GetDexFileDeps(*dex_file);
+ const DexFileDeps& other_deps = *other.GetDexFileDeps(*dex_file);
+ // We currently collect extra strings only on the main `VerifierDeps`,
+ // which should be the one passed as `this` in this method.
+ DCHECK(other_deps.strings_.empty());
+ MergeSets(my_deps->assignable_types_, other_deps.assignable_types_);
+ MergeSets(my_deps->unassignable_types_, other_deps.unassignable_types_);
+ MergeSets(my_deps->classes_, other_deps.classes_);
+ MergeSets(my_deps->fields_, other_deps.fields_);
+ MergeSets(my_deps->direct_methods_, other_deps.direct_methods_);
+ MergeSets(my_deps->virtual_methods_, other_deps.virtual_methods_);
+ MergeSets(my_deps->interface_methods_, other_deps.interface_methods_);
+ for (dex::TypeIndex entry : other_deps.unverified_classes_) {
+ my_deps->unverified_classes_.push_back(entry);
+ }
+ }
+}
+
VerifierDeps::DexFileDeps* VerifierDeps::GetDexFileDeps(const DexFile& dex_file) {
auto it = dex_deps_.find(&dex_file);
return (it == dex_deps_.end()) ? nullptr : it->second.get();
@@ -56,17 +80,114 @@
}
}
-template <typename T>
-uint32_t VerifierDeps::GetDeclaringClassStringId(const DexFile& dex_file, T* element) {
+uint32_t VerifierDeps::GetClassDescriptorStringId(const DexFile& dex_file,
+ ObjPtr<mirror::Class> klass) {
+ DCHECK(klass != nullptr);
+ ObjPtr<mirror::DexCache> dex_cache = klass->GetDexCache();
+ // Array and proxy classes do not have a dex cache.
+ if (!klass->IsArrayClass() && !klass->IsProxyClass()) {
+ DCHECK(dex_cache != nullptr) << klass->PrettyClass();
+ if (dex_cache->GetDexFile() == &dex_file) {
+ // FindStringId is slow, try to go through the class def if we have one.
+ const DexFile::ClassDef* class_def = klass->GetClassDef();
+ DCHECK(class_def != nullptr) << klass->PrettyClass();
+ const DexFile::TypeId& type_id = dex_file.GetTypeId(class_def->class_idx_);
+ if (kIsDebugBuild) {
+ std::string temp;
+ CHECK_EQ(GetIdFromString(dex_file, klass->GetDescriptor(&temp)), type_id.descriptor_idx_);
+ }
+ return type_id.descriptor_idx_;
+ }
+ }
+ std::string temp;
+ return GetIdFromString(dex_file, klass->GetDescriptor(&temp));
+}
+
+// Try to find the string descriptor of the class. type_idx is a best guess of a matching string id.
+static uint32_t TryGetClassDescriptorStringId(const DexFile& dex_file,
+ dex::TypeIndex type_idx,
+ ObjPtr<mirror::Class> klass)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ if (!klass->IsArrayClass()) {
+ const DexFile::TypeId& type_id = dex_file.GetTypeId(type_idx);
+ const DexFile& klass_dex = klass->GetDexFile();
+ const DexFile::TypeId& klass_type_id = klass_dex.GetTypeId(klass->GetClassDef()->class_idx_);
+ if (strcmp(dex_file.GetTypeDescriptor(type_id),
+ klass_dex.GetTypeDescriptor(klass_type_id)) == 0) {
+ return type_id.descriptor_idx_;
+ }
+ }
+ return DexFile::kDexNoIndex;
+}
+
+uint32_t VerifierDeps::GetMethodDeclaringClassStringId(const DexFile& dex_file,
+ uint32_t dex_method_index,
+ ArtMethod* method) {
static_assert(kAccJavaFlagsMask == 0xFFFF, "Unexpected value of a constant");
- if (element == nullptr) {
+ if (method == nullptr) {
return VerifierDeps::kUnresolvedMarker;
- } else {
- std::string temp;
- uint32_t string_id = GetIdFromString(
- dex_file, element->GetDeclaringClass()->GetDescriptor(&temp));
+ }
+ const uint32_t string_id = TryGetClassDescriptorStringId(
+ dex_file,
+ dex_file.GetMethodId(dex_method_index).class_idx_,
+ method->GetDeclaringClass());
+ if (string_id != DexFile::kDexNoIndex) {
+ // Got lucky using the original dex file, return based on the input dex file.
+ DCHECK_EQ(GetClassDescriptorStringId(dex_file, method->GetDeclaringClass()), string_id);
return string_id;
}
+ return GetClassDescriptorStringId(dex_file, method->GetDeclaringClass());
+}
+
+uint32_t VerifierDeps::GetFieldDeclaringClassStringId(const DexFile& dex_file,
+ uint32_t dex_field_idx,
+ ArtField* field) {
+ static_assert(kAccJavaFlagsMask == 0xFFFF, "Unexpected value of a constant");
+ if (field == nullptr) {
+ return VerifierDeps::kUnresolvedMarker;
+ }
+ const uint32_t string_id = TryGetClassDescriptorStringId(
+ dex_file,
+ dex_file.GetFieldId(dex_field_idx).class_idx_,
+ field->GetDeclaringClass());
+ if (string_id != DexFile::kDexNoIndex) {
+ // Got lucky using the original dex file, return based on the input dex file.
+ DCHECK_EQ(GetClassDescriptorStringId(dex_file, field->GetDeclaringClass()), string_id);
+ return string_id;
+ }
+ return GetClassDescriptorStringId(dex_file, field->GetDeclaringClass());
+}
+
+static inline VerifierDeps* GetMainVerifierDeps() {
+ // The main VerifierDeps is the one set in the compiler callbacks, which at the
+ // end of verification will have all the per-thread VerifierDeps merged into it.
+ CompilerCallbacks* callbacks = Runtime::Current()->GetCompilerCallbacks();
+ if (callbacks == nullptr) {
+ return nullptr;
+ }
+ return callbacks->GetVerifierDeps();
+}
+
+static inline VerifierDeps* GetThreadLocalVerifierDeps() {
+ // During AOT, each thread has its own VerifierDeps, to avoid lock contention. At the end
+ // of full verification, these VerifierDeps will be merged into the main one.
+ if (!Runtime::Current()->IsAotCompiler()) {
+ return nullptr;
+ }
+ return Thread::Current()->GetVerifierDeps();
+}
+
+static bool FindExistingStringId(const std::vector<std::string>& strings,
+ const std::string& str,
+ uint32_t* found_id) {
+ uint32_t num_extra_ids = strings.size();
+ for (size_t i = 0; i < num_extra_ids; ++i) {
+ if (strings[i] == str) {
+ *found_id = i;
+ return true;
+ }
+ }
+ return false;
}
uint32_t VerifierDeps::GetIdFromString(const DexFile& dex_file, const std::string& str) {
@@ -79,25 +200,32 @@
// String is not in the DEX file. Assign a new ID to it which is higher than
// the number of strings in the DEX file.
- DexFileDeps* deps = GetDexFileDeps(dex_file);
+ // We use the main `VerifierDeps` for adding new strings to simplify
+ // synchronization/merging of these entries between threads.
+ VerifierDeps* singleton = GetMainVerifierDeps();
+ DexFileDeps* deps = singleton->GetDexFileDeps(dex_file);
DCHECK(deps != nullptr);
uint32_t num_ids_in_dex = dex_file.NumStringIds();
- uint32_t num_extra_ids = deps->strings_.size();
+ uint32_t found_id;
- for (size_t i = 0; i < num_extra_ids; ++i) {
- if (deps->strings_[i] == str) {
- return num_ids_in_dex + i;
+ {
+ ReaderMutexLock mu(Thread::Current(), *Locks::verifier_deps_lock_);
+ if (FindExistingStringId(deps->strings_, str, &found_id)) {
+ return num_ids_in_dex + found_id;
}
}
-
- deps->strings_.push_back(str);
-
- uint32_t new_id = num_ids_in_dex + num_extra_ids;
- CHECK_GE(new_id, num_ids_in_dex); // check for overflows
- DCHECK_EQ(str, GetStringFromId(dex_file, new_id));
-
- return new_id;
+ {
+ WriterMutexLock mu(Thread::Current(), *Locks::verifier_deps_lock_);
+ if (FindExistingStringId(deps->strings_, str, &found_id)) {
+ return num_ids_in_dex + found_id;
+ }
+ deps->strings_.push_back(str);
+ uint32_t new_id = num_ids_in_dex + deps->strings_.size() - 1;
+ CHECK_GE(new_id, num_ids_in_dex); // check for overflows
+ DCHECK_EQ(str, singleton->GetStringFromId(dex_file, new_id));
+ return new_id;
+ }
}
std::string VerifierDeps::GetStringFromId(const DexFile& dex_file, uint32_t string_id) const {
@@ -137,7 +265,7 @@
}
void VerifierDeps::AddClassResolution(const DexFile& dex_file,
- uint16_t type_idx,
+ dex::TypeIndex type_idx,
mirror::Class* klass) {
DexFileDeps* dex_deps = GetDexFileDeps(dex_file);
if (dex_deps == nullptr) {
@@ -151,7 +279,6 @@
return;
}
- MutexLock mu(Thread::Current(), *Locks::verifier_deps_lock_);
dex_deps->classes_.emplace(ClassResolution(type_idx, GetAccessFlags(klass)));
}
@@ -170,9 +297,11 @@
return;
}
- MutexLock mu(Thread::Current(), *Locks::verifier_deps_lock_);
- dex_deps->fields_.emplace(FieldResolution(
- field_idx, GetAccessFlags(field), GetDeclaringClassStringId(dex_file, field)));
+ dex_deps->fields_.emplace(FieldResolution(field_idx,
+ GetAccessFlags(field),
+ GetFieldDeclaringClassStringId(dex_file,
+ field_idx,
+ field)));
}
void VerifierDeps::AddMethodResolution(const DexFile& dex_file,
@@ -191,10 +320,9 @@
return;
}
- MutexLock mu(Thread::Current(), *Locks::verifier_deps_lock_);
MethodResolution method_tuple(method_idx,
GetAccessFlags(method),
- GetDeclaringClassStringId(dex_file, method));
+ GetMethodDeclaringClassStringId(dex_file, method_idx, method));
if (resolution_kind == kDirectMethodResolution) {
dex_deps->direct_methods_.emplace(method_tuple);
} else if (resolution_kind == kVirtualMethodResolution) {
@@ -260,15 +388,9 @@
return;
}
- MutexLock mu(Thread::Current(), *Locks::verifier_deps_lock_);
-
// Get string IDs for both descriptors and store in the appropriate set.
-
- std::string temp1, temp2;
- std::string destination_desc(destination->GetDescriptor(&temp1));
- std::string source_desc(source->GetDescriptor(&temp2));
- uint32_t destination_id = GetIdFromString(dex_file, destination_desc);
- uint32_t source_id = GetIdFromString(dex_file, source_desc);
+ uint32_t destination_id = GetClassDescriptorStringId(dex_file, destination);
+ uint32_t source_id = GetClassDescriptorStringId(dex_file, source);
if (is_assignable) {
dex_deps->assignable_types_.emplace(TypeAssignability(destination_id, source_id));
@@ -277,45 +399,36 @@
}
}
-static inline VerifierDeps* GetVerifierDepsSingleton() {
- CompilerCallbacks* callbacks = Runtime::Current()->GetCompilerCallbacks();
- if (callbacks == nullptr) {
- return nullptr;
- }
- return callbacks->GetVerifierDeps();
-}
-
void VerifierDeps::MaybeRecordVerificationStatus(const DexFile& dex_file,
- uint16_t type_idx,
+ dex::TypeIndex type_idx,
MethodVerifier::FailureKind failure_kind) {
if (failure_kind == MethodVerifier::kNoFailure) {
// We only record classes that did not fully verify at compile time.
return;
}
- VerifierDeps* singleton = GetVerifierDepsSingleton();
- if (singleton != nullptr) {
- DexFileDeps* dex_deps = singleton->GetDexFileDeps(dex_file);
- MutexLock mu(Thread::Current(), *Locks::verifier_deps_lock_);
+ VerifierDeps* thread_deps = GetThreadLocalVerifierDeps();
+ if (thread_deps != nullptr) {
+ DexFileDeps* dex_deps = thread_deps->GetDexFileDeps(dex_file);
dex_deps->unverified_classes_.push_back(type_idx);
}
}
void VerifierDeps::MaybeRecordClassResolution(const DexFile& dex_file,
- uint16_t type_idx,
+ dex::TypeIndex type_idx,
mirror::Class* klass) {
- VerifierDeps* singleton = GetVerifierDepsSingleton();
- if (singleton != nullptr) {
- singleton->AddClassResolution(dex_file, type_idx, klass);
+ VerifierDeps* thread_deps = GetThreadLocalVerifierDeps();
+ if (thread_deps != nullptr) {
+ thread_deps->AddClassResolution(dex_file, type_idx, klass);
}
}
void VerifierDeps::MaybeRecordFieldResolution(const DexFile& dex_file,
uint32_t field_idx,
ArtField* field) {
- VerifierDeps* singleton = GetVerifierDepsSingleton();
- if (singleton != nullptr) {
- singleton->AddFieldResolution(dex_file, field_idx, field);
+ VerifierDeps* thread_deps = GetThreadLocalVerifierDeps();
+ if (thread_deps != nullptr) {
+ thread_deps->AddFieldResolution(dex_file, field_idx, field);
}
}
@@ -323,9 +436,9 @@
uint32_t method_idx,
MethodResolutionKind resolution_kind,
ArtMethod* method) {
- VerifierDeps* singleton = GetVerifierDepsSingleton();
- if (singleton != nullptr) {
- singleton->AddMethodResolution(dex_file, method_idx, resolution_kind, method);
+ VerifierDeps* thread_deps = GetThreadLocalVerifierDeps();
+ if (thread_deps != nullptr) {
+ thread_deps->AddMethodResolution(dex_file, method_idx, resolution_kind, method);
}
}
@@ -334,42 +447,68 @@
mirror::Class* source,
bool is_strict,
bool is_assignable) {
- VerifierDeps* singleton = GetVerifierDepsSingleton();
- if (singleton != nullptr) {
- singleton->AddAssignability(dex_file, destination, source, is_strict, is_assignable);
+ VerifierDeps* thread_deps = GetThreadLocalVerifierDeps();
+ if (thread_deps != nullptr) {
+ thread_deps->AddAssignability(dex_file, destination, source, is_strict, is_assignable);
}
}
+namespace {
+
static inline uint32_t DecodeUint32WithOverflowCheck(const uint8_t** in, const uint8_t* end) {
CHECK_LT(*in, end);
return DecodeUnsignedLeb128(in);
}
+template<typename T> inline uint32_t Encode(T in);
+
+template<> inline uint32_t Encode<uint16_t>(uint16_t in) {
+ return in;
+}
+template<> inline uint32_t Encode<uint32_t>(uint32_t in) {
+ return in;
+}
+template<> inline uint32_t Encode<dex::TypeIndex>(dex::TypeIndex in) {
+ return in.index_;
+}
+
+template<typename T> inline T Decode(uint32_t in);
+
+template<> inline uint16_t Decode<uint16_t>(uint32_t in) {
+ return dchecked_integral_cast<uint16_t>(in);
+}
+template<> inline uint32_t Decode<uint32_t>(uint32_t in) {
+ return in;
+}
+template<> inline dex::TypeIndex Decode<dex::TypeIndex>(uint32_t in) {
+ return dex::TypeIndex(in);
+}
+
template<typename T1, typename T2>
static inline void EncodeTuple(std::vector<uint8_t>* out, const std::tuple<T1, T2>& t) {
- EncodeUnsignedLeb128(out, std::get<0>(t));
- EncodeUnsignedLeb128(out, std::get<1>(t));
+ EncodeUnsignedLeb128(out, Encode(std::get<0>(t)));
+ EncodeUnsignedLeb128(out, Encode(std::get<1>(t)));
}
template<typename T1, typename T2>
static inline void DecodeTuple(const uint8_t** in, const uint8_t* end, std::tuple<T1, T2>* t) {
- T1 v1 = static_cast<T1>(DecodeUint32WithOverflowCheck(in, end));
- T2 v2 = static_cast<T2>(DecodeUint32WithOverflowCheck(in, end));
+ T1 v1 = Decode<T1>(DecodeUint32WithOverflowCheck(in, end));
+ T2 v2 = Decode<T2>(DecodeUint32WithOverflowCheck(in, end));
*t = std::make_tuple(v1, v2);
}
template<typename T1, typename T2, typename T3>
static inline void EncodeTuple(std::vector<uint8_t>* out, const std::tuple<T1, T2, T3>& t) {
- EncodeUnsignedLeb128(out, std::get<0>(t));
- EncodeUnsignedLeb128(out, std::get<1>(t));
- EncodeUnsignedLeb128(out, std::get<2>(t));
+ EncodeUnsignedLeb128(out, Encode(std::get<0>(t)));
+ EncodeUnsignedLeb128(out, Encode(std::get<1>(t)));
+ EncodeUnsignedLeb128(out, Encode(std::get<2>(t)));
}
template<typename T1, typename T2, typename T3>
static inline void DecodeTuple(const uint8_t** in, const uint8_t* end, std::tuple<T1, T2, T3>* t) {
- T1 v1 = static_cast<T1>(DecodeUint32WithOverflowCheck(in, end));
- T2 v2 = static_cast<T2>(DecodeUint32WithOverflowCheck(in, end));
- T3 v3 = static_cast<T2>(DecodeUint32WithOverflowCheck(in, end));
+ T1 v1 = Decode<T1>(DecodeUint32WithOverflowCheck(in, end));
+ T2 v2 = Decode<T2>(DecodeUint32WithOverflowCheck(in, end));
+ T3 v3 = Decode<T2>(DecodeUint32WithOverflowCheck(in, end));
*t = std::make_tuple(v1, v2, v3);
}
@@ -381,11 +520,12 @@
}
}
+template <typename T>
static inline void EncodeUint16Vector(std::vector<uint8_t>* out,
- const std::vector<uint16_t>& vector) {
+ const std::vector<T>& vector) {
EncodeUnsignedLeb128(out, vector.size());
- for (uint16_t entry : vector) {
- EncodeUnsignedLeb128(out, entry);
+ for (const T& entry : vector) {
+ EncodeUnsignedLeb128(out, Encode(entry));
}
}
@@ -400,14 +540,16 @@
}
}
+template<typename T>
static inline void DecodeUint16Vector(const uint8_t** in,
const uint8_t* end,
- std::vector<uint16_t>* vector) {
+ std::vector<T>* vector) {
DCHECK(vector->empty());
size_t num_entries = DecodeUint32WithOverflowCheck(in, end);
vector->reserve(num_entries);
for (size_t i = 0; i < num_entries; ++i) {
- vector->push_back(dchecked_integral_cast<uint16_t>(DecodeUint32WithOverflowCheck(in, end)));
+ vector->push_back(
+ Decode<T>(dchecked_integral_cast<uint16_t>(DecodeUint32WithOverflowCheck(in, end))));
}
}
@@ -436,9 +578,10 @@
}
}
+} // namespace
+
void VerifierDeps::Encode(const std::vector<const DexFile*>& dex_files,
std::vector<uint8_t>* buffer) const {
- MutexLock mu(Thread::Current(), *Locks::verifier_deps_lock_);
for (const DexFile* dex_file : dex_files) {
const DexFileDeps& deps = *GetDexFileDeps(*dex_file);
EncodeStringVector(buffer, deps.strings_);
@@ -480,8 +623,6 @@
}
bool VerifierDeps::Equals(const VerifierDeps& rhs) const {
- MutexLock mu(Thread::Current(), *Locks::verifier_deps_lock_);
-
if (dex_deps_.size() != rhs.dex_deps_.size()) {
return false;
}
@@ -599,7 +740,7 @@
}
}
- for (uint16_t type_index : dep.second->unverified_classes_) {
+ for (dex::TypeIndex type_index : dep.second->unverified_classes_) {
vios->Stream()
<< dex_file.StringByTypeIdx(type_index)
<< " is expected to be verified at runtime\n";
diff --git a/runtime/verifier/verifier_deps.h b/runtime/verifier/verifier_deps.h
index 7b419d4..a12071b 100644
--- a/runtime/verifier/verifier_deps.h
+++ b/runtime/verifier/verifier_deps.h
@@ -42,29 +42,30 @@
// which are being compiled. Classes defined in DEX files outside of this set
// (or synthesized classes without associated DEX files) are considered being
// in the classpath.
-// During code-flow verification, the MethodVerifier informs the VerifierDeps
-// singleton about the outcome of every resolution and assignability test, and
-// the singleton records them if their outcome may change with changes in the
-// classpath.
+// During code-flow verification, the MethodVerifier informs VerifierDeps
+// about the outcome of every resolution and assignability test, and
+// the VerifierDeps object records them if their outcome may change with
+// changes in the classpath.
class VerifierDeps {
public:
- explicit VerifierDeps(const std::vector<const DexFile*>& dex_files)
- REQUIRES(!Locks::verifier_deps_lock_);
+ explicit VerifierDeps(const std::vector<const DexFile*>& dex_files);
- VerifierDeps(const std::vector<const DexFile*>& dex_files,
- ArrayRef<const uint8_t> data)
- REQUIRES(!Locks::verifier_deps_lock_);
+ VerifierDeps(const std::vector<const DexFile*>& dex_files, ArrayRef<const uint8_t> data);
+
+ // Merge `other` into this `VerifierDeps`'. `other` and `this` must be for the
+ // same set of dex files.
+ void MergeWith(const VerifierDeps& other, const std::vector<const DexFile*>& dex_files);
// Record the verification status of the class at `type_idx`.
static void MaybeRecordVerificationStatus(const DexFile& dex_file,
- uint16_t type_idx,
+ dex::TypeIndex type_idx,
MethodVerifier::FailureKind failure_kind)
REQUIRES(!Locks::verifier_deps_lock_);
// Record the outcome `klass` of resolving type `type_idx` from `dex_file`.
// If `klass` is null, the class is assumed unresolved.
static void MaybeRecordClassResolution(const DexFile& dex_file,
- uint16_t type_idx,
+ dex::TypeIndex type_idx,
mirror::Class* klass)
REQUIRES_SHARED(Locks::mutator_lock_)
REQUIRES(!Locks::verifier_deps_lock_);
@@ -101,38 +102,30 @@
// Serialize the recorded dependencies and store the data into `buffer`.
// `dex_files` provides the order of the dex files in which the dependencies
// should be emitted.
- void Encode(const std::vector<const DexFile*>& dex_files, std::vector<uint8_t>* buffer) const
- REQUIRES(!Locks::verifier_deps_lock_);
+ void Encode(const std::vector<const DexFile*>& dex_files, std::vector<uint8_t>* buffer) const;
- // NO_THREAD_SAFETY_ANALYSIS as Dump iterates over dex_deps_, which is guarded by
- // verifier_deps_lock_, but we expect Dump to be called once the deps collection is done.
- void Dump(VariableIndentationOutputStream* vios) const
- NO_THREAD_SAFETY_ANALYSIS;
+ void Dump(VariableIndentationOutputStream* vios) const;
// Verify the encoded dependencies of this `VerifierDeps` are still valid.
- // NO_THREAD_SAFETY_ANALYSIS, as this must be called on a read-only `VerifierDeps`.
bool ValidateDependencies(Handle<mirror::ClassLoader> class_loader, Thread* self) const
- NO_THREAD_SAFETY_ANALYSIS;
+ REQUIRES_SHARED(Locks::mutator_lock_);
- // NO_THREAD_SAFETY_ANALSYS, as this is queried when the VerifierDeps are
- // fully created.
- const std::vector<uint16_t>& GetUnverifiedClasses(const DexFile& dex_file) const
- NO_THREAD_SAFETY_ANALYSIS {
+ const std::vector<dex::TypeIndex>& GetUnverifiedClasses(const DexFile& dex_file) const {
return GetDexFileDeps(dex_file)->unverified_classes_;
}
private:
static constexpr uint16_t kUnresolvedMarker = static_cast<uint16_t>(-1);
- using ClassResolutionBase = std::tuple<uint32_t, uint16_t>;
+ using ClassResolutionBase = std::tuple<dex::TypeIndex, uint16_t>;
struct ClassResolution : public ClassResolutionBase {
ClassResolution() = default;
ClassResolution(const ClassResolution&) = default;
- ClassResolution(uint32_t type_idx, uint16_t access_flags)
+ ClassResolution(dex::TypeIndex type_idx, uint16_t access_flags)
: ClassResolutionBase(type_idx, access_flags) {}
bool IsResolved() const { return GetAccessFlags() != kUnresolvedMarker; }
- uint32_t GetDexTypeIndex() const { return std::get<0>(*this); }
+ dex::TypeIndex GetDexTypeIndex() const { return std::get<0>(*this); }
uint16_t GetAccessFlags() const { return std::get<1>(*this); }
};
@@ -193,20 +186,16 @@
std::set<MethodResolution> interface_methods_;
// List of classes that were not fully verified in that dex file.
- std::vector<uint16_t> unverified_classes_;
+ std::vector<dex::TypeIndex> unverified_classes_;
bool Equals(const DexFileDeps& rhs) const;
};
// Finds the DexFileDep instance associated with `dex_file`, or nullptr if
// `dex_file` is not reported as being compiled.
- // We disable thread safety analysis. The method only reads the key set of
- // `dex_deps_` which stays constant after initialization.
- DexFileDeps* GetDexFileDeps(const DexFile& dex_file)
- NO_THREAD_SAFETY_ANALYSIS;
+ DexFileDeps* GetDexFileDeps(const DexFile& dex_file);
- const DexFileDeps* GetDexFileDeps(const DexFile& dex_file) const
- NO_THREAD_SAFETY_ANALYSIS;
+ const DexFileDeps* GetDexFileDeps(const DexFile& dex_file) const;
// Returns true if `klass` is null or not defined in any of dex files which
// were reported as being compiled.
@@ -218,11 +207,10 @@
// of the corresponding DexFileDeps structure (either provided or inferred from
// `dex_file`).
uint32_t GetIdFromString(const DexFile& dex_file, const std::string& str)
- REQUIRES(Locks::verifier_deps_lock_);
+ REQUIRES(!Locks::verifier_deps_lock_);
// Returns the string represented by `id`.
- std::string GetStringFromId(const DexFile& dex_file, uint32_t string_id) const
- REQUIRES(Locks::verifier_deps_lock_);
+ std::string GetStringFromId(const DexFile& dex_file, uint32_t string_id) const;
// Returns the bytecode access flags of `element` (bottom 16 bits), or
// `kUnresolvedMarker` if `element` is null.
@@ -232,13 +220,22 @@
// Returns a string ID of the descriptor of the declaring class of `element`,
// or `kUnresolvedMarker` if `element` is null.
- template <typename T>
- uint32_t GetDeclaringClassStringId(const DexFile& dex_file, T* element)
+ uint32_t GetMethodDeclaringClassStringId(const DexFile& dex_file,
+ uint32_t dex_method_idx,
+ ArtMethod* method)
+ REQUIRES_SHARED(Locks::mutator_lock_);
+ uint32_t GetFieldDeclaringClassStringId(const DexFile& dex_file,
+ uint32_t dex_field_idx,
+ ArtField* field)
+ REQUIRES_SHARED(Locks::mutator_lock_);
+
+ // Returns a string ID of the descriptor of the class.
+ uint32_t GetClassDescriptorStringId(const DexFile& dex_file, ObjPtr<mirror::Class> klass)
REQUIRES_SHARED(Locks::mutator_lock_)
- REQUIRES(Locks::verifier_deps_lock_);
+ REQUIRES(!Locks::verifier_deps_lock_);
void AddClassResolution(const DexFile& dex_file,
- uint16_t type_idx,
+ dex::TypeIndex type_idx,
mirror::Class* klass)
REQUIRES_SHARED(Locks::mutator_lock_)
REQUIRES(!Locks::verifier_deps_lock_);
@@ -261,11 +258,9 @@
mirror::Class* source,
bool is_strict,
bool is_assignable)
- REQUIRES_SHARED(Locks::mutator_lock_)
- REQUIRES(!Locks::verifier_deps_lock_);
+ REQUIRES_SHARED(Locks::mutator_lock_);
- bool Equals(const VerifierDeps& rhs) const
- REQUIRES(!Locks::verifier_deps_lock_);
+ bool Equals(const VerifierDeps& rhs) const;
// Verify `dex_file` according to the `deps`, that is going over each
// `DexFileDeps` field, and checking that the recorded information still
@@ -274,16 +269,14 @@
const DexFile& dex_file,
const DexFileDeps& deps,
Thread* self) const
- REQUIRES_SHARED(Locks::mutator_lock_)
- REQUIRES(Locks::verifier_deps_lock_);
+ REQUIRES_SHARED(Locks::mutator_lock_);
bool VerifyAssignability(Handle<mirror::ClassLoader> class_loader,
const DexFile& dex_file,
const std::set<TypeAssignability>& assignables,
bool expected_assignability,
Thread* self) const
- REQUIRES_SHARED(Locks::mutator_lock_)
- REQUIRES(Locks::verifier_deps_lock_);
+ REQUIRES_SHARED(Locks::mutator_lock_);
// Verify that the set of resolved classes at the point of creation
// of this `VerifierDeps` is still the same.
@@ -291,8 +284,7 @@
const DexFile& dex_file,
const std::set<ClassResolution>& classes,
Thread* self) const
- REQUIRES_SHARED(Locks::mutator_lock_)
- REQUIRES(Locks::verifier_deps_lock_);
+ REQUIRES_SHARED(Locks::mutator_lock_);
// Verify that the set of resolved fields at the point of creation
// of this `VerifierDeps` is still the same, and each field resolves to the
@@ -302,7 +294,7 @@
const std::set<FieldResolution>& classes,
Thread* self) const
REQUIRES_SHARED(Locks::mutator_lock_)
- REQUIRES(Locks::verifier_deps_lock_);
+ REQUIRES(!Locks::verifier_deps_lock_);
// Verify that the set of resolved methods at the point of creation
// of this `VerifierDeps` is still the same, and each method resolves to the
@@ -312,12 +304,10 @@
const std::set<MethodResolution>& methods,
MethodResolutionKind kind,
Thread* self) const
- REQUIRES_SHARED(Locks::mutator_lock_)
- REQUIRES(Locks::verifier_deps_lock_);
+ REQUIRES_SHARED(Locks::mutator_lock_);
// Map from DexFiles into dependencies collected from verification of their methods.
- std::map<const DexFile*, std::unique_ptr<DexFileDeps>> dex_deps_
- GUARDED_BY(Locks::verifier_deps_lock_);
+ std::map<const DexFile*, std::unique_ptr<DexFileDeps>> dex_deps_;
friend class VerifierDepsTest;
ART_FRIEND_TEST(VerifierDepsTest, StringToId);
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/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/538-checker-embed-constants/src/Main.java b/test/538-checker-embed-constants/src/Main.java
index 02c609e..6b25747 100644
--- a/test/538-checker-embed-constants/src/Main.java
+++ b/test/538-checker-embed-constants/src/Main.java
@@ -30,7 +30,7 @@
/// CHECK-START-ARM: int Main.and255(int) disassembly (after)
/// CHECK-NOT: movs {{r\d+}}, #255
- /// CHECK: and {{r\d+}}, {{r\d+}}, #255
+ /// CHECK: and {{r\d+}}, {{r\d+}}, #0xff
public static int and255(int arg) {
return arg & 255;
@@ -46,7 +46,7 @@
/// CHECK-START-ARM: int Main.andNot15(int) disassembly (after)
/// CHECK-NOT: mvn {{r\d+}}, #15
- /// CHECK: bic {{r\d+}}, {{r\d+}}, #15
+ /// CHECK: bic {{r\d+}}, {{r\d+}}, #0xf
public static int andNot15(int arg) {
return arg & ~15;
@@ -54,7 +54,7 @@
/// CHECK-START-ARM: int Main.or255(int) disassembly (after)
/// CHECK-NOT: movs {{r\d+}}, #255
- /// CHECK: orr {{r\d+}}, {{r\d+}}, #255
+ /// CHECK: orr {{r\d+}}, {{r\d+}}, #0xff
public static int or255(int arg) {
return arg | 255;
@@ -70,7 +70,7 @@
/// CHECK-START-ARM: int Main.orNot15(int) disassembly (after)
/// CHECK-NOT: mvn {{r\d+}}, #15
- /// CHECK: orn {{r\d+}}, {{r\d+}}, #15
+ /// CHECK: orn {{r\d+}}, {{r\d+}}, #0xf
public static int orNot15(int arg) {
return arg | ~15;
@@ -78,7 +78,7 @@
/// CHECK-START-ARM: int Main.xor255(int) disassembly (after)
/// CHECK-NOT: movs {{r\d+}}, #255
- /// CHECK: eor {{r\d+}}, {{r\d+}}, #255
+ /// CHECK: eor {{r\d+}}, {{r\d+}}, #0xff
public static int xor255(int arg) {
return arg ^ 255;
@@ -104,7 +104,7 @@
/// CHECK-NOT: movs {{r\d+}}, #255
/// CHECK-NOT: and{{(\.w)?}}
/// CHECK-NOT: bic{{(\.w)?}}
- /// CHECK-DAG: and {{r\d+}}, {{r\d+}}, #255
+ /// CHECK-DAG: and {{r\d+}}, {{r\d+}}, #0xff
/// CHECK-DAG: movs {{r\d+}}, #0
/// CHECK-NOT: and{{(\.w)?}}
/// CHECK-NOT: bic{{(\.w)?}}
@@ -131,7 +131,7 @@
/// CHECK-NOT: mvn {{r\d+}}, #15
/// CHECK-NOT: and{{(\.w)?}}
/// CHECK-NOT: bic{{(\.w)?}}
- /// CHECK: bic {{r\d+}}, {{r\d+}}, #15
+ /// CHECK: bic {{r\d+}}, {{r\d+}}, #0xf
/// CHECK-NOT: and{{(\.w)?}}
/// CHECK-NOT: bic{{(\.w)?}}
@@ -144,8 +144,8 @@
/// CHECK-NOT: mvn {{r\d+}}, #15
/// CHECK-NOT: and{{(\.w)?}}
/// CHECK-NOT: bic{{(\.w)?}}
- /// CHECK-DAG: and {{r\d+}}, {{r\d+}}, #15
- /// CHECK-DAG: bic {{r\d+}}, {{r\d+}}, #15
+ /// CHECK-DAG: and {{r\d+}}, {{r\d+}}, #0xf
+ /// CHECK-DAG: bic {{r\d+}}, {{r\d+}}, #0xf
/// CHECK-NOT: and{{(\.w)?}}
/// CHECK-NOT: bic{{(\.w)?}}
@@ -157,7 +157,7 @@
/// CHECK-NOT: movs {{r\d+}}, #255
/// CHECK-NOT: orr{{(\.w)?}}
/// CHECK-NOT: orn
- /// CHECK: orr {{r\d+}}, {{r\d+}}, #255
+ /// CHECK: orr {{r\d+}}, {{r\d+}}, #0xff
/// CHECK-NOT: orr{{(\.w)?}}
/// CHECK-NOT: orn
@@ -183,7 +183,7 @@
/// CHECK-NOT: mvn {{r\d+}}, #15
/// CHECK-NOT: orr{{(\.w)?}}
/// CHECK-NOT: orn
- /// CHECK-DAG: orn {{r\d+}}, {{r\d+}}, #15
+ /// CHECK-DAG: orn {{r\d+}}, {{r\d+}}, #0xf
/// CHECK-DAG: mvn {{r\d+}}, #0
/// CHECK-NOT: orr{{(\.w)?}}
/// CHECK-NOT: orn
@@ -197,8 +197,8 @@
/// CHECK-NOT: mvn {{r\d+}}, #15
/// CHECK-NOT: orr{{(\.w)?}}
/// CHECK-NOT: orn
- /// CHECK-DAG: orr {{r\d+}}, {{r\d+}}, #15
- /// CHECK-DAG: orn {{r\d+}}, {{r\d+}}, #15
+ /// CHECK-DAG: orr {{r\d+}}, {{r\d+}}, #0xf
+ /// CHECK-DAG: orn {{r\d+}}, {{r\d+}}, #0xf
/// CHECK-NOT: orr{{(\.w)?}}
/// CHECK-NOT: orn
@@ -209,7 +209,7 @@
/// CHECK-START-ARM: long Main.xor255(long) disassembly (after)
/// CHECK-NOT: movs {{r\d+}}, #255
/// CHECK-NOT: eor{{(\.w)?}}
- /// CHECK: eor {{r\d+}}, {{r\d+}}, #255
+ /// CHECK: eor {{r\d+}}, {{r\d+}}, #0xff
/// CHECK-NOT: eor{{(\.w)?}}
public static long xor255(long arg) {
@@ -257,8 +257,8 @@
/// CHECK-NOT: movs {{r\d+}}, #15
/// CHECK-NOT: mov.w {{r\d+}}, #-268435456
/// CHECK-NOT: eor{{(\.w)?}}
- /// CHECK-DAG: eor {{r\d+}}, {{r\d+}}, #15
- /// CHECK-DAG: eor {{r\d+}}, {{r\d+}}, #4026531840
+ /// CHECK-DAG: eor {{r\d+}}, {{r\d+}}, #0xf
+ /// CHECK-DAG: eor {{r\d+}}, {{r\d+}}, #0xf0000000
/// CHECK-NOT: eor{{(\.w)?}}
public static long xor0xf00000000000000f(long arg) {
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/626-set-resolved-string/expected.txt b/test/626-set-resolved-string/expected.txt
new file mode 100644
index 0000000..f4983b5
--- /dev/null
+++ b/test/626-set-resolved-string/expected.txt
@@ -0,0 +1,2 @@
+JNI_OnLoad called
+foo
diff --git a/test/626-set-resolved-string/info.txt b/test/626-set-resolved-string/info.txt
new file mode 100644
index 0000000..e3a512f
--- /dev/null
+++ b/test/626-set-resolved-string/info.txt
@@ -0,0 +1,3 @@
+Test that even if Java code calls DexCache.setResolvedString and does
+not strongly intern the given string, the JIT will ensure that the
+strings it references are strongly interned.
diff --git a/test/626-set-resolved-string/src/Main.java b/test/626-set-resolved-string/src/Main.java
new file mode 100644
index 0000000..868b9d1
--- /dev/null
+++ b/test/626-set-resolved-string/src/Main.java
@@ -0,0 +1,48 @@
+/*
+ * 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.
+ */
+
+import java.lang.reflect.Method;
+
+public class Main {
+ public static void main(String[] args) {
+ System.loadLibrary(args[0]);
+
+ // Get all methods. We cannot call getDeclaredMethod("foo") as
+ // that would make "foo" a strong root.
+ Method[] methods = Main.class.getDeclaredMethods();
+
+ // Call getName on the methods, which is implemented by using the dex
+ // cache and calling setResolvedString.
+ for (int i = 0; i < methods.length; i++) {
+ methods[i].getName();
+ }
+
+ // Compile Main.foo. "foo" needs to be a strong root for JIT compilation.
+ // We stress test this:
+ // - avoid strongly interning "foo" by doing "f" + "oo"
+ // - call GC so that weaks can be collected.
+ // - invoke foo() to make sure "foo" hasn't been collected.
+ ensureJitCompiled(Main.class, "f" + "oo");
+ Runtime.getRuntime().gc();
+ foo();
+ }
+
+ public static void foo() {
+ System.out.println("foo");
+ }
+
+ public static native void ensureJitCompiled(Class cls, String method_name);
+}
diff --git a/test/628-vdex/expected.txt b/test/628-vdex/expected.txt
new file mode 100644
index 0000000..d0f61f6
--- /dev/null
+++ b/test/628-vdex/expected.txt
@@ -0,0 +1,2 @@
+In foo
+In foo
diff --git a/test/628-vdex/info.txt b/test/628-vdex/info.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/628-vdex/info.txt
diff --git a/test/103-string-append/run b/test/628-vdex/run
old mode 100755
new mode 100644
similarity index 77%
rename from test/103-string-append/run
rename to test/628-vdex/run
index e27a622..f1b0a95
--- a/test/103-string-append/run
+++ b/test/628-vdex/run
@@ -1,6 +1,6 @@
#!/bin/bash
#
-# Copyright (C) 2012 The Android Open Source Project
+# Copyright (C) 2016 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -14,5 +14,4 @@
# 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}"
+exec ${RUN} --vdex "${@}"
diff --git a/test/628-vdex/src/Main.java b/test/628-vdex/src/Main.java
new file mode 100644
index 0000000..7ceab2c
--- /dev/null
+++ b/test/628-vdex/src/Main.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+public class Main {
+ Main() {
+ // Will be quickened with RETURN_VOID_NO_BARRIER.
+ }
+
+ public static void main(String[] args) {
+ 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) {
+ System.out.println("In foo");
+ }
+}
+
diff --git a/test/910-methods/methods.cc b/test/910-methods/methods.cc
index 8f0850b..3ed91d7 100644
--- a/test/910-methods/methods.cc
+++ b/test/910-methods/methods.cc
@@ -66,6 +66,15 @@
jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(gen));
}
+ // Also run GetMethodName with all parameter pointers null to check for segfaults.
+ jvmtiError result2 = jvmti_env->GetMethodName(id, nullptr, nullptr, nullptr);
+ if (result2 != JVMTI_ERROR_NONE) {
+ char* err;
+ jvmti_env->GetErrorName(result2, &err);
+ printf("Failure running GetMethodName(null, null, null): %s\n", err);
+ return nullptr;
+ }
+
return ret;
}
diff --git a/test/913-heaps/expected.txt b/test/913-heaps/expected.txt
index d1ddbae..8002cfa 100644
--- a/test/913-heaps/expected.txt
+++ b/test/913-heaps/expected.txt
@@ -45,7 +45,7 @@
6@1000 --(class)--> 1000@0 [size=123, length=-1]
---
root@root --(jni-global)--> 1@1000 [size=16, length=-1]
-root@root --(jni-local)--> 1@1000 [size=16, length=-1]
+root@root --(jni-local[id=1,tag=3000,depth=0,method=followReferences])--> 1@1000 [size=16, length=-1]
root@root --(stack-local)--> 1@1000 [size=16, length=-1]
root@root --(thread)--> 1@1000 [size=16, length=-1]
root@root --(thread)--> 3000@0 [size=132, length=-1]
@@ -67,7 +67,7 @@
6@1000 --(class)--> 1000@0 [size=123, length=-1]
---
root@root --(jni-global)--> 1@1000 [size=16, length=-1]
-root@root --(jni-local)--> 1@1000 [size=16, length=-1]
+root@root --(jni-local[id=1,tag=3000,depth=0,method=followReferences])--> 1@1000 [size=16, length=-1]
root@root --(stack-local)--> 1@1000 [size=16, length=-1]
root@root --(stack-local)--> 2@1000 [size=16, length=-1]
root@root --(thread)--> 1@1000 [size=16, length=-1]
diff --git a/test/913-heaps/heaps.cc b/test/913-heaps/heaps.cc
index 0c627d6..340671d 100644
--- a/test/913-heaps/heaps.cc
+++ b/test/913-heaps/heaps.cc
@@ -185,20 +185,229 @@
}
}
- 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_;
+ };
+
+ class JNILocalElement : public Elem {
+ public:
+ JNILocalElement(const std::string& referrer,
+ const std::string& referree,
+ jlong size,
+ jint length,
+ const jvmtiHeapReferenceInfo* reference_info)
+ : Elem(referrer, referree, size, length) {
+ memcpy(&info_, reference_info, sizeof(jvmtiHeapReferenceInfo));
+ }
+
+ protected:
+ std::string PrintArrowType() const OVERRIDE {
+ char* name = nullptr;
+ if (info_.jni_local.method != nullptr) {
+ jvmti_env->GetMethodName(info_.jni_local.method, &name, nullptr, nullptr);
+ }
+ std::string ret = StringPrintf("jni-local[id=%" PRId64 ",tag=%" PRId64 ",depth=%d,"
+ "method=%s]",
+ info_.jni_local.thread_id,
+ info_.jni_local.thread_tag,
+ info_.jni_local.depth,
+ name == nullptr ? "<null>" : name);
+ if (name != nullptr) {
+ jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(name));
+ }
+
+ return ret;
+ }
+
+ private:
+ const std::string string_;
+ jvmtiHeapReferenceInfo info_;
+ };
+
+ // 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 JNILocalElement(referrer,
+ referree,
+ size,
+ length,
+ reference_info));
+ 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 +418,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 +438,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 +465,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/expected.txt b/test/956-methodhandles/expected.txt
index 0a5caa1..9b09327 100644
--- a/test/956-methodhandles/expected.txt
+++ b/test/956-methodhandles/expected.txt
@@ -7,3 +7,11 @@
String constructors done.
testReferenceReturnValueConversions done.
testPrimitiveReturnValueConversions done.
+Hi
+Hi
+Hi
+Hi
+Expect Hi here: Hi
+Don't expect Hi now
+[3, 2, 1]
+[1, 2, 3]
diff --git a/test/956-methodhandles/src/Main.java b/test/956-methodhandles/src/Main.java
index aab9f50..ee9c436 100644
--- a/test/956-methodhandles/src/Main.java
+++ b/test/956-methodhandles/src/Main.java
@@ -19,16 +19,20 @@
import java.lang.invoke.MethodHandles.Lookup;
import java.lang.invoke.MethodType;
import java.lang.invoke.WrongMethodTypeException;
-import java.nio.charset.Charset;
-import java.nio.charset.StandardCharsets;
-
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
public class Main {
public static class A {
+ public A() {}
+
public void foo() {
System.out.println("foo_A");
}
@@ -65,11 +69,13 @@
testfindSpecial_invokeDirectBehaviour();
testExceptionDetailMessages();
testfindVirtual();
+ testfindStatic();
testUnreflects();
testAsType();
testConstructors();
testStringConstructors();
testReturnValueConversions();
+ testVariableArity();
}
public static void testfindSpecial_invokeSuperBehaviour() throws Throwable {
@@ -116,6 +122,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 +208,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 +262,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 +317,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 {
@@ -481,6 +557,34 @@
}
}
+ public static void assertTrue(boolean value) {
+ if (!value) {
+ throw new AssertionError("assertTrue value: " + value);
+ }
+ }
+
+ public static void assertFalse(boolean value) {
+ if (value) {
+ throw new AssertionError("assertTrue value: " + value);
+ }
+ }
+
+ public static void assertEquals(int i1, int i2) {
+ if (i1 == i2) { return; }
+ throw new AssertionError("assertEquals i1: " + i1 + ", i2: " + i2);
+ }
+
+ public static void assertEquals(long i1, long i2) {
+ if (i1 == i2) { return; }
+ throw new AssertionError("assertEquals l1: " + i1 + ", l2: " + i2);
+ }
+
+ public static void assertEquals(Object o, Object p) {
+ if (o == p) { return; }
+ if (o != null && p != null && o.equals(p)) { return; }
+ throw new AssertionError("assertEquals: o1: " + o + ", o2: " + p);
+ }
+
public static void assertEquals(String s1, String s2) {
if (s1 == s2) {
return;
@@ -886,4 +990,480 @@
testReferenceReturnValueConversions();
testPrimitiveReturnValueConversions();
}
+
+ public static class BaseVariableArityTester {
+ public String update(Float f0, Float... floats) {
+ return "base " + f0 + ", " + Arrays.toString(floats);
+ }
+ }
+
+ public static class VariableArityTester extends BaseVariableArityTester {
+ private String lastResult;
+
+ // Constructors
+ public VariableArityTester() {}
+ public VariableArityTester(boolean... booleans) { update(booleans); }
+ public VariableArityTester(byte... bytes) { update(bytes); }
+ public VariableArityTester(char... chars) { update(chars); }
+ public VariableArityTester(short... shorts) { update(shorts); }
+ public VariableArityTester(int... ints) { update(ints); }
+ public VariableArityTester(long... longs) { update(longs); }
+ public VariableArityTester(float... floats) { update(floats); }
+ public VariableArityTester(double... doubles) { update(doubles); }
+ public VariableArityTester(Float f0, Float... floats) { update(f0, floats); }
+ public VariableArityTester(String s0, String... strings) { update(s0, strings); }
+ public VariableArityTester(char c, Number... numbers) { update(c, numbers); }
+ @SafeVarargs
+ public VariableArityTester(ArrayList<Integer> l0, ArrayList<Integer>... lists) {
+ update(l0, lists);
+ }
+ public VariableArityTester(List l0, List... lists) { update(l0, lists); }
+
+ // Methods
+ public String update(boolean... booleans) { return lastResult = tally(booleans); }
+ public String update(byte... bytes) { return lastResult = tally(bytes); }
+ public String update(char... chars) { return lastResult = tally(chars); }
+ public String update(short... shorts) { return lastResult = tally(shorts); }
+ public String update(int... ints) {
+ lastResult = tally(ints);
+ return lastResult;
+ }
+ public String update(long... longs) { return lastResult = tally(longs); }
+ public String update(float... floats) { return lastResult = tally(floats); }
+ public String update(double... doubles) { return lastResult = tally(doubles); }
+ @Override
+ public String update(Float f0, Float... floats) { return lastResult = tally(f0, floats); }
+ public String update(String s0, String... strings) { return lastResult = tally(s0, strings); }
+ public String update(char c, Number... numbers) { return lastResult = tally(c, numbers); }
+ @SafeVarargs
+ public final String update(ArrayList<Integer> l0, ArrayList<Integer>... lists) {
+ lastResult = tally(l0, lists);
+ return lastResult;
+ }
+ public String update(List l0, List... lists) { return lastResult = tally(l0, lists); }
+
+ public String arrayMethod(Object[] o) {
+ return Arrays.deepToString(o);
+ }
+
+ public String lastResult() { return lastResult; }
+
+ // Static Methods
+ public static String tally(boolean... booleans) { return Arrays.toString(booleans); }
+ public static String tally(byte... bytes) { return Arrays.toString(bytes); }
+ public static String tally(char... chars) { return Arrays.toString(chars); }
+ public static String tally(short... shorts) { return Arrays.toString(shorts); }
+ public static String tally(int... ints) { return Arrays.toString(ints); }
+ public static String tally(long... longs) { return Arrays.toString(longs); }
+ public static String tally(float... floats) { return Arrays.toString(floats); }
+ public static String tally(double... doubles) { return Arrays.toString(doubles); }
+ public static String tally(Float f0, Float... floats) {
+ return f0 + ", " + Arrays.toString(floats);
+ }
+ public static String tally(String s0, String... strings) {
+ return s0 + ", " + Arrays.toString(strings);
+ }
+ public static String tally(char c, Number... numbers) {
+ return c + ", " + Arrays.toString(numbers);
+ }
+ @SafeVarargs
+ public static String tally(ArrayList<Integer> l0, ArrayList<Integer>... lists) {
+ return Arrays.toString(l0.toArray()) + ", " + Arrays.deepToString(lists);
+ }
+ public static String tally(List l0, List... lists) {
+ return Arrays.deepToString(l0.toArray()) + ", " + Arrays.deepToString(lists);
+ }
+ public static void foo(int... ints) { System.out.println(Arrays.toString(ints)); }
+ public static long sumToPrimitive(int... ints) {
+ long result = 0;
+ for (int i : ints) result += i;
+ return result;
+ }
+ public static Long sumToReference(int... ints) {
+ System.err.println("Hi");
+ return new Long(sumToPrimitive(ints));
+ }
+ public static MethodHandles.Lookup lookup() {
+ return MethodHandles.lookup();
+ }
+ }
+
+ // This method only exists to fool Jack's handling of types. See b/32536744.
+ public static Object getAsObject(String[] strings) {
+ return (Object) strings;
+ }
+
+ public static void testVariableArity() throws Throwable {
+ MethodHandle mh;
+ VariableArityTester vat = new VariableArityTester();
+
+ assertEquals("[1]", vat.update(1));
+ assertEquals("[1, 1]", vat.update(1, 1));
+ assertEquals("[1, 1, 1]", vat.update(1, 1, 1));
+
+ // Methods - boolean
+ mh = MethodHandles.lookup().findVirtual(VariableArityTester.class, "update",
+ MethodType.methodType(String.class, boolean[].class));
+ assertTrue(mh.isVarargsCollector());
+ assertFalse(mh.asFixedArity().isVarargsCollector());
+ assertEquals("[]", mh.invoke(vat));
+ assertEquals("[true, false, true]", mh.invoke(vat, true, false, true));
+ assertEquals("[true, false, true]", mh.invoke(vat, new boolean[] { true, false, true}));
+ assertEquals("[false, true]", mh.invoke(vat, Boolean.valueOf(false), Boolean.valueOf(true)));
+ try {
+ mh.invoke(vat, true, true, 0);
+ fail();
+ } catch (WrongMethodTypeException e) {}
+ try {
+ assertEquals("[false, true]", mh.invoke(vat, Boolean.valueOf(false), (Boolean) null));
+ fail();
+ } catch (NullPointerException e) {}
+
+ // Methods - byte
+ mh = MethodHandles.lookup().findVirtual(VariableArityTester.class, "update",
+ MethodType.methodType(String.class, byte[].class));
+ assertTrue(mh.isVarargsCollector());
+ assertEquals("[]", mh.invoke(vat));
+ assertEquals("[32, 64, 97]", mh.invoke(vat, (byte) 32, Byte.valueOf((byte) 64), (byte) 97));
+ assertEquals("[32, 64, 97]", mh.invoke(vat, new byte[] {(byte) 32, (byte) 64, (byte) 97}));
+ try {
+ mh.invoke(vat, (byte) 1, Integer.valueOf(3), (byte) 0);
+ fail();
+ } catch (WrongMethodTypeException e) {}
+
+ // Methods - char
+ mh = MethodHandles.lookup().findVirtual(VariableArityTester.class, "update",
+ MethodType.methodType(String.class, char[].class));
+ assertTrue(mh.isVarargsCollector());
+ assertEquals("[]", mh.invoke(vat));
+ assertEquals("[A, B, C]", mh.invoke(vat, 'A', Character.valueOf('B'), 'C'));
+ assertEquals("[W, X, Y, Z]", mh.invoke(vat, new char[] { 'W', 'X', 'Y', 'Z' }));
+
+ // Methods - short
+ mh = MethodHandles.lookup().findVirtual(VariableArityTester.class, "update",
+ MethodType.methodType(String.class, short[].class));
+ assertTrue(mh.isVarargsCollector());
+ assertEquals("[]", mh.invoke(vat));
+ assertEquals("[32767, -32768, 0]",
+ mh.invoke(vat, Short.MAX_VALUE, Short.MIN_VALUE, Short.valueOf((short) 0)));
+ assertEquals("[1, -1]", mh.invoke(vat, new short[] { (short) 1, (short) -1 }));
+
+ // Methods - int
+ mh = MethodHandles.lookup().findVirtual(VariableArityTester.class, "update",
+ MethodType.methodType(String.class, int[].class));
+ assertTrue(mh.isVarargsCollector());
+ assertEquals("[]", mh.invoke(vat));
+ assertEquals("[0, 2147483647, -2147483648, 0]",
+ mh.invoke(vat, Integer.valueOf(0), Integer.MAX_VALUE, Integer.MIN_VALUE, 0));
+ assertEquals("[0, -1, 1, 0]", mh.invoke(vat, new int[] { 0, -1, 1, 0 }));
+
+ assertEquals("[5, 4, 3, 2, 1]", (String) mh.invokeExact(vat, new int [] { 5, 4, 3, 2, 1 }));
+ try {
+ assertEquals("[5, 4, 3, 2, 1]", (String) mh.invokeExact(vat, 5, 4, 3, 2, 1));
+ fail();
+ } catch (WrongMethodTypeException e) {}
+ assertEquals("[5, 4, 3, 2, 1]", (String) mh.invoke(vat, 5, 4, 3, 2, 1));
+
+ // Methods - long
+ mh = MethodHandles.lookup().findVirtual(VariableArityTester.class, "update",
+ MethodType.methodType(String.class, long[].class));
+ assertTrue(mh.isVarargsCollector());
+ assertEquals("[]", mh.invoke(vat));
+ assertEquals("[0, 9223372036854775807, -9223372036854775808]",
+ mh.invoke(vat, Long.valueOf(0), Long.MAX_VALUE, Long.MIN_VALUE));
+ assertEquals("[0, -1, 1, 0]", mh.invoke(vat, new long[] { 0, -1, 1, 0 }));
+
+ // Methods - float
+ mh = MethodHandles.lookup().findVirtual(VariableArityTester.class, "update",
+ MethodType.methodType(String.class, float[].class));
+ assertTrue(mh.isVarargsCollector());
+ assertEquals("[]", mh.invoke(vat));
+ assertEquals("[0.0, 1.25, -1.25]",
+ mh.invoke(vat, 0.0f, Float.valueOf(1.25f), Float.valueOf(-1.25f)));
+ assertEquals("[0.0, -1.0, 1.0, 0.0]",
+ mh.invoke(vat, new float[] { 0.0f, -1.0f, 1.0f, 0.0f }));
+
+ // Methods - double
+ mh = MethodHandles.lookup().findVirtual(VariableArityTester.class, "update",
+ MethodType.methodType(String.class, double[].class));
+ assertTrue(mh.isVarargsCollector());
+ assertEquals("[]", mh.invoke(vat));
+ assertEquals("[0.0, 1.25, -1.25]",
+ mh.invoke(vat, 0.0, Double.valueOf(1.25), Double.valueOf(-1.25)));
+ assertEquals("[0.0, -1.0, 1.0, 0.0]",
+ mh.invoke(vat, new double[] { 0.0, -1.0, 1.0, 0.0 }));
+ mh.invoke(vat, 0.3f, 1.33, 1.33);
+
+ // Methods - String
+ mh = MethodHandles.lookup().
+ findVirtual(VariableArityTester.class, "update",
+ MethodType.methodType(String.class, String.class, String[].class));
+ assertTrue(mh.isVarargsCollector());
+ assertEquals("Echidna, []", mh.invoke(vat, "Echidna"));
+ assertEquals("Bongo, [Jerboa, Okapi]",
+ mh.invoke(vat, "Bongo", "Jerboa", "Okapi"));
+
+ // Methods - Float
+ mh = MethodHandles.lookup().
+ findVirtual(VariableArityTester.class, "update",
+ MethodType.methodType(String.class, Float.class, Float[].class));
+ assertTrue(mh.isVarargsCollector());
+ assertEquals("9.99, [0.0, 0.1, 1.1]",
+ (String) mh.invoke(vat, Float.valueOf(9.99f),
+ new Float[] { Float.valueOf(0.0f),
+ Float.valueOf(0.1f),
+ Float.valueOf(1.1f) }));
+ assertEquals("9.99, [0.0, 0.1, 1.1]",
+ (String) mh.invoke(vat, Float.valueOf(9.99f), Float.valueOf(0.0f),
+ Float.valueOf(0.1f), Float.valueOf(1.1f)));
+ assertEquals("9.99, [0.0, 0.1, 1.1]",
+ (String) mh.invoke(vat, Float.valueOf(9.99f), 0.0f, 0.1f, 1.1f));
+ try {
+ assertEquals("9.99, [77.0, 33.0, 64.0]",
+ (String) mh.invoke(vat, Float.valueOf(9.99f), 77, 33, 64));
+ fail();
+ } catch (WrongMethodTypeException e) {}
+ assertEquals("9.99, [0.0, 0.1, 1.1]",
+ (String) mh.invokeExact(vat, Float.valueOf(9.99f),
+ new Float[] { Float.valueOf(0.0f),
+ Float.valueOf(0.1f),
+ Float.valueOf(1.1f) }));
+ assertEquals("9.99, [0.0, null, 1.1]",
+ (String) mh.invokeExact(vat, Float.valueOf(9.99f),
+ new Float[] { Float.valueOf(0.0f),
+ null,
+ Float.valueOf(1.1f) }));
+ try {
+ assertEquals("9.99, [0.0, 0.1, 1.1]",
+ (String) mh.invokeExact(vat, Float.valueOf(9.99f), 0.0f, 0.1f, 1.1f));
+ fail();
+ } catch (WrongMethodTypeException e) {}
+
+ // Methods - Number
+ mh = MethodHandles.lookup().
+ findVirtual(VariableArityTester.class, "update",
+ MethodType.methodType(String.class, char.class, Number[].class));
+ assertTrue(mh.isVarargsCollector());
+ assertFalse(mh.asFixedArity().isVarargsCollector());
+ assertEquals("x, []", (String) mh.invoke(vat, 'x'));
+ assertEquals("x, [3.141]", (String) mh.invoke(vat, 'x', 3.141));
+ assertEquals("x, [null, 3.131, 37]",
+ (String) mh.invoke(vat, 'x', null, 3.131, new Integer(37)));
+ try {
+ assertEquals("x, [null, 3.131, bad, 37]",
+ (String) mh.invoke(vat, 'x', null, 3.131, "bad", new Integer(37)));
+ assertTrue(false);
+ fail();
+ } catch (ClassCastException e) {}
+ try {
+ assertEquals("x, [null, 3.131, bad, 37]",
+ (String) mh.invoke(
+ vat, 'x', (Process) null, 3.131, "bad", new Integer(37)));
+ assertTrue(false);
+ fail();
+ } catch (ClassCastException e) {}
+
+ // Methods - an array method that is not variable arity.
+ mh = MethodHandles.lookup().findVirtual(
+ VariableArityTester.class, "arrayMethod",
+ MethodType.methodType(String.class, Object[].class));
+ assertFalse(mh.isVarargsCollector());
+ mh.invoke(vat, new Object[] { "123" });
+ try {
+ assertEquals("-", mh.invoke(vat, new Float(3), new Float(4)));
+ fail();
+ } catch (WrongMethodTypeException e) {}
+ mh = mh.asVarargsCollector(Object[].class);
+ assertTrue(mh.isVarargsCollector());
+ assertEquals("[3.0, 4.0]", (String) mh.invoke(vat, new Float(3), new Float(4)));
+
+ // Constructors - default
+ mh = MethodHandles.lookup().findConstructor(
+ VariableArityTester.class, MethodType.methodType(void.class));
+ assertFalse(mh.isVarargsCollector());
+
+ // Constructors - boolean
+ mh = MethodHandles.lookup().findConstructor(
+ VariableArityTester.class, MethodType.methodType(void.class, boolean[].class));
+ assertTrue(mh.isVarargsCollector());
+ assertEquals("[true, true, false]",
+ ((VariableArityTester) mh.invoke(new boolean[] {true, true, false})).lastResult());
+ assertEquals("[true, true, false]",
+ ((VariableArityTester) mh.invoke(true, true, false)).lastResult());
+ try {
+ assertEquals("[true, true, false]",
+ ((VariableArityTester) mh.invokeExact(true, true, false)).lastResult());
+ fail();
+ } catch (WrongMethodTypeException e) {}
+
+ // Constructors - byte
+ mh = MethodHandles.lookup().findConstructor(
+ VariableArityTester.class, MethodType.methodType(void.class, byte[].class));
+ assertTrue(mh.isVarargsCollector());
+ assertEquals("[55, 66, 60]",
+ ((VariableArityTester)
+ mh.invoke(new byte[] {(byte) 55, (byte) 66, (byte) 60})).lastResult());
+ assertEquals("[55, 66, 60]",
+ ((VariableArityTester) mh.invoke(
+ (byte) 55, (byte) 66, (byte) 60)).lastResult());
+ try {
+ assertEquals("[55, 66, 60]",
+ ((VariableArityTester) mh.invokeExact(
+ (byte) 55, (byte) 66, (byte) 60)).lastResult());
+ fail();
+ } catch (WrongMethodTypeException e) {}
+ try {
+ assertEquals("[3, 3]",
+ ((VariableArityTester) mh.invoke(
+ new Number[] { Byte.valueOf((byte) 3), (byte) 3})).lastResult());
+ fail();
+ } catch (WrongMethodTypeException e) {}
+
+ // Constructors - String (have a different path than other reference types).
+ mh = MethodHandles.lookup().findConstructor(
+ VariableArityTester.class, MethodType.methodType(void.class, String.class, String[].class));
+ assertTrue(mh.isVarargsCollector());
+ assertEquals("x, []", ((VariableArityTester) mh.invoke("x")).lastResult());
+ assertEquals("x, [y]", ((VariableArityTester) mh.invoke("x", "y")).lastResult());
+ assertEquals("x, [y, z]",
+ ((VariableArityTester) mh.invoke("x", new String[] { "y", "z" })).lastResult());
+ try {
+ assertEquals("x, [y]", ((VariableArityTester) mh.invokeExact("x", "y")).lastResult());
+ fail();
+ } catch (WrongMethodTypeException e) {}
+ assertEquals("x, [null, z]",
+ ((VariableArityTester) mh.invoke("x", new String[] { null, "z" })).lastResult());
+
+ // Constructors - Number
+ mh = MethodHandles.lookup().findConstructor(
+ VariableArityTester.class, MethodType.methodType(void.class, char.class, Number[].class));
+ assertTrue(mh.isVarargsCollector());
+ assertFalse(mh.asFixedArity().isVarargsCollector());
+ assertEquals("x, []", ((VariableArityTester) mh.invoke('x')).lastResult());
+ assertEquals("x, [3.141]", ((VariableArityTester) mh.invoke('x', 3.141)).lastResult());
+ assertEquals("x, [null, 3.131, 37]",
+ ((VariableArityTester) mh.invoke('x', null, 3.131, new Integer(37))).lastResult());
+ try {
+ assertEquals("x, [null, 3.131, bad, 37]",
+ ((VariableArityTester) mh.invoke(
+ 'x', null, 3.131, "bad", new Integer(37))).lastResult());
+ assertTrue(false);
+ fail();
+ } catch (ClassCastException e) {}
+ try {
+ assertEquals("x, [null, 3.131, bad, 37]",
+ ((VariableArityTester) mh.invoke(
+ 'x', (Process) null, 3.131, "bad", new Integer(37))).lastResult());
+ assertTrue(false);
+ fail();
+ } catch (ClassCastException e) {}
+
+ // Static Methods - Float
+ mh = MethodHandles.lookup().
+ findStatic(VariableArityTester.class, "tally",
+ MethodType.methodType(String.class, Float.class, Float[].class));
+ assertTrue(mh.isVarargsCollector());
+ assertEquals("9.99, [0.0, 0.1, 1.1]",
+ (String) mh.invoke(Float.valueOf(9.99f),
+ new Float[] { Float.valueOf(0.0f),
+ Float.valueOf(0.1f),
+ Float.valueOf(1.1f) }));
+ assertEquals("9.99, [0.0, 0.1, 1.1]",
+ (String) mh.invoke(Float.valueOf(9.99f), Float.valueOf(0.0f),
+ Float.valueOf(0.1f), Float.valueOf(1.1f)));
+ assertEquals("9.99, [0.0, 0.1, 1.1]",
+ (String) mh.invoke(Float.valueOf(9.99f), 0.0f, 0.1f, 1.1f));
+ try {
+ assertEquals("9.99, [77.0, 33.0, 64.0]",
+ (String) mh.invoke(Float.valueOf(9.99f), 77, 33, 64));
+ fail();
+ } catch (WrongMethodTypeException e) {}
+ assertEquals("9.99, [0.0, 0.1, 1.1]",
+ (String) mh.invokeExact(Float.valueOf(9.99f),
+ new Float[] { Float.valueOf(0.0f),
+ Float.valueOf(0.1f),
+ Float.valueOf(1.1f) }));
+ assertEquals("9.99, [0.0, null, 1.1]",
+ (String) mh.invokeExact(Float.valueOf(9.99f),
+ new Float[] { Float.valueOf(0.0f),
+ null,
+ Float.valueOf(1.1f) }));
+ try {
+ assertEquals("9.99, [0.0, 0.1, 1.1]",
+ (String) mh.invokeExact(Float.valueOf(9.99f), 0.0f, 0.1f, 1.1f));
+ fail();
+ } catch (WrongMethodTypeException e) {}
+
+ // Special methods - Float
+ mh = VariableArityTester.lookup().
+ findSpecial(BaseVariableArityTester.class, "update",
+ MethodType.methodType(String.class, Float.class, Float[].class),
+ VariableArityTester.class);
+ assertTrue(mh.isVarargsCollector());
+ assertEquals("base 9.99, [0.0, 0.1, 1.1]",
+ (String) mh.invoke(vat,
+ Float.valueOf(9.99f),
+ new Float[] { Float.valueOf(0.0f),
+ Float.valueOf(0.1f),
+ Float.valueOf(1.1f) }));
+ assertEquals("base 9.99, [0.0, 0.1, 1.1]",
+ (String) mh.invoke(vat, Float.valueOf(9.99f), Float.valueOf(0.0f),
+ Float.valueOf(0.1f), Float.valueOf(1.1f)));
+
+ // Return value conversions.
+ mh = MethodHandles.lookup().findVirtual(VariableArityTester.class, "update",
+ MethodType.methodType(String.class, int[].class));
+ assertEquals("[1, 2, 3]", (String) mh.invoke(vat, 1, 2, 3));
+ assertEquals("[1, 2, 3]", (Object) mh.invoke(vat, 1, 2, 3));
+ try {
+ assertEquals("[1, 2, 3, 4]", (long) mh.invoke(vat, 1, 2, 3));
+ fail();
+ } catch (WrongMethodTypeException e) {}
+ assertEquals("[1, 2, 3]", vat.lastResult());
+ mh = MethodHandles.lookup().findStatic(VariableArityTester.class, "sumToPrimitive",
+ MethodType.methodType(long.class, int[].class));
+ assertEquals(10l, (long) mh.invoke(1, 2, 3, 4));
+ assertEquals(Long.valueOf(10l), (Long) mh.invoke(1, 2, 3, 4));
+ mh = MethodHandles.lookup().findStatic(VariableArityTester.class, "sumToReference",
+ MethodType.methodType(Long.class, int[].class));
+ Object o = mh.invoke(1, 2, 3, 4);
+ long l = (long) mh.invoke(1, 2, 3, 4);
+ assertEquals(10l, (long) mh.invoke(1, 2, 3, 4));
+ assertEquals(Long.valueOf(10l), (Long) mh.invoke(1, 2, 3, 4));
+ try {
+ // WrongMethodTypeException should be raised before invoke here.
+ System.err.print("Expect Hi here: ");
+ assertEquals(Long.valueOf(10l), (Byte) mh.invoke(1, 2, 3, 4));
+ fail();
+ } catch (ClassCastException e) {}
+ try {
+ // WrongMethodTypeException should be raised before invoke here.
+ System.err.println("Don't expect Hi now");
+ byte b = (byte) mh.invoke(1, 2, 3, 4);
+ fail();
+ } catch (WrongMethodTypeException e) {}
+
+ // Return void produces 0 / null.
+ mh = MethodHandles.lookup().findStatic(VariableArityTester.class, "foo",
+ MethodType.methodType(void.class, int[].class));
+ assertEquals(null, (Object) mh.invoke(3, 2, 1));
+ assertEquals(0l, (long) mh.invoke(1, 2, 3));
+
+ // Combinators
+ mh = MethodHandles.lookup().findVirtual(VariableArityTester.class, "update",
+ MethodType.methodType(String.class, boolean[].class));
+ assertTrue(mh.isVarargsCollector());
+ mh = mh.bindTo(vat);
+ assertFalse(mh.isVarargsCollector());
+ mh = mh.asVarargsCollector(boolean[].class);
+ assertTrue(mh.isVarargsCollector());
+ assertEquals("[]", mh.invoke());
+ assertEquals("[true, false, true]", mh.invoke(true, false, true));
+ assertEquals("[true, false, true]", mh.invoke(new boolean[] { true, false, true}));
+ assertEquals("[false, true]", mh.invoke(Boolean.valueOf(false), Boolean.valueOf(true)));
+ try {
+ mh.invoke(true, true, 0);
+ fail();
+ } catch (WrongMethodTypeException e) {}
+ }
}
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..96b984d 100644
--- a/test/Android.run-test.mk
+++ b/test/Android.run-test.mk
@@ -608,10 +608,7 @@
TEST_ART_BROKEN_INTERPRETER_READ_BARRIER_RUN_TESTS :=
# Tests that should fail in the read barrier configuration with the Optimizing compiler (AOT).
-# 484: Baker's fast path based read barrier compiler instrumentation generates code containing
-# more parallel moves on x86, thus some Checker assertions may fail.
-TEST_ART_BROKEN_OPTIMIZING_READ_BARRIER_RUN_TESTS := \
- 484-checker-register-hints
+TEST_ART_BROKEN_OPTIMIZING_READ_BARRIER_RUN_TESTS :=
# Tests that should fail in the read barrier configuration with JIT (Optimizing compiler).
TEST_ART_BROKEN_JIT_READ_BARRIER_RUN_TESTS :=
@@ -791,6 +788,10 @@
TEST_ART_TARGET_SYNC_DEPS += $(OUT_DIR)/$(ART_TEST_LIST_device_$(TARGET_2ND_ARCH)_libnativebridgetest)
endif
+# Also need libopenjdkjvmti.
+TEST_ART_TARGET_SYNC_DEPS += libopenjdkjvmti
+TEST_ART_TARGET_SYNC_DEPS += libopenjdkjvmtid
+
# All tests require the host executables. The tests also depend on the core images, but on
# specific version depending on the compiler.
ART_TEST_HOST_RUN_TEST_DEPENDENCIES := \
@@ -804,7 +805,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 +820,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..bb3a3ad 100755
--- a/test/etc/run-test-jar
+++ b/test/etc/run-test-jar
@@ -58,6 +58,7 @@
ARGS=""
EXTERNAL_LOG_TAGS="n" # if y respect externally set ANDROID_LOG_TAGS.
DRY_RUN="n" # if y prepare to run the test but don't run it.
+TEST_VDEX="n"
while true; do
if [ "x$1" = "x--quiet" ]; then
@@ -243,6 +244,9 @@
elif [ "x$1" = "x--dry-run" ]; then
DRY_RUN="y"
shift
+ elif [ "x$1" = "x--vdex" ]; then
+ TEST_VDEX="y"
+ shift
elif expr "x$1" : "x--" >/dev/null 2>&1; then
echo "unknown $0 option: $1" 1>&2
exit 1
@@ -444,6 +448,7 @@
fi
dex2oat_cmdline="true"
+vdex_cmdline="true"
mkdir_locations="${DEX_LOCATION}/dalvik-cache/$ISA"
strip_cmdline="true"
@@ -473,6 +478,9 @@
# Use -k 1m to SIGKILL it a minute later if it hasn't ended.
dex2oat_cmdline="timeout -k 1m -s SIGRTMIN+2 1m ${dex2oat_cmdline}"
fi
+ if [ "$TEST_VDEX" = "y" ]; then
+ vdex_cmdline="${dex2oat_cmdline} --input-vdex=$DEX_LOCATION/oat/$ISA/$TEST_NAME.vdex"
+ fi
fi
if [ "$STRIP_DEX" = "y" ]; then
@@ -513,6 +521,7 @@
# Remove whitespace.
dex2oat_cmdline=$(echo $dex2oat_cmdline)
dalvikvm_cmdline=$(echo $dalvikvm_cmdline)
+vdex_cmdline=$(echo $vdex_cmdline)
if [ "$HOST" = "n" ]; then
adb root > /dev/null
@@ -553,6 +562,7 @@
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH && \
export PATH=$ANDROID_ROOT/bin:$PATH && \
$dex2oat_cmdline && \
+ $vdex_cmdline && \
$strip_cmdline && \
$dalvikvm_cmdline"
@@ -626,7 +636,7 @@
fi
if [ "$DEV_MODE" = "y" ]; then
- echo "mkdir -p ${mkdir_locations} && $dex2oat_cmdline && $strip_cmdline && $cmdline"
+ echo "mkdir -p ${mkdir_locations} && $dex2oat_cmdline && $vdex_cmdline && $strip_cmdline && $cmdline"
fi
cd $ANDROID_BUILD_TOP
@@ -634,6 +644,7 @@
rm -rf ${DEX_LOCATION}/dalvik-cache/
mkdir -p ${mkdir_locations} || exit 1
$dex2oat_cmdline || { echo "Dex2oat failed." >&2 ; exit 2; }
+ $vdex_cmdline || { echo "Dex2oat failed." >&2 ; exit 2; }
$strip_cmdline || { echo "Strip failed." >&2 ; exit 3; }
# For running, we must turn off logging when dex2oat or patchoat are missing. Otherwise we use
diff --git a/test/run-test b/test/run-test
index 37eefb3..ea9622a 100755
--- a/test/run-test
+++ b/test/run-test
@@ -351,6 +351,9 @@
elif [ "x$1" = "x--bisection-search" ]; then
bisection_search="yes"
shift
+ elif [ "x$1" = "x--vdex" ]; then
+ run_args="${run_args} --vdex"
+ shift
elif expr "x$1" : "x--" >/dev/null 2>&1; then
echo "unknown $0 option: $1" 1>&2
usage="yes"
@@ -640,6 +643,7 @@
echo " --pic-test Compile the test code position independent."
echo " --quiet Don't print anything except failure messages"
echo " --bisection-search Perform bisection bug search."
+ echo " --vdex Test using vdex as in input to dex2oat. Only works with --prebuild."
) 1>&2 # Direct to stderr so usage is not printed if --quiet is set.
exit 1
fi
diff --git a/tools/ahat/Android.mk b/tools/ahat/Android.mk
index 27c2054..493eafb 100644
--- a/tools/ahat/Android.mk
+++ b/tools/ahat/Android.mk
@@ -48,7 +48,7 @@
include $(CLEAR_VARS)
LOCAL_SRC_FILES := $(call all-java-files-under, test)
LOCAL_JAR_MANIFEST := test/manifest.txt
-LOCAL_STATIC_JAVA_LIBRARIES := ahat junit
+LOCAL_STATIC_JAVA_LIBRARIES := ahat junit-host
LOCAL_IS_HOST_MODULE := true
LOCAL_MODULE_TAGS := tests
LOCAL_MODULE := ahat-tests
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"
diff --git a/tools/dexfuzz/README b/tools/dexfuzz/README
index a0658ec..c1cdf1e 100644
--- a/tools/dexfuzz/README
+++ b/tools/dexfuzz/README
@@ -4,7 +4,7 @@
DexFuzz is primarily a tool for fuzzing DEX files. Fuzzing is the introduction of
subtle changes ("mutations") to a file to produce a new test case. These test cases
can be used to test the various modes of execution available to ART (Interpreter,
-Quick compiler, Optimizing compiler) to check for bugs in these modes of execution.
+Optimizing compiler) to check for bugs in these modes of execution.
This is done by differential testing - each test file is executed with each mode of
execution, and any differences between the resulting outputs may be an indication of
a bug in one of the modes.
@@ -53,17 +53,16 @@
And also at least two of the following backends:
--interpreter
- --quick
--optimizing
Note that if you wanted to test both ARM and ARM64 on an ARM64 device, you can use
--allarm. Also in this case only one backend is needed, if i.e., you wanted to test
-ARM Quick Backend vs. ARM64 Quick Backend.
+ARM Optimizing Backend vs. ARM64 Optimizing Backend.
Some legal examples:
- --arm --quick --optimizing
- --x86 --quick --optimizing --interpreter
- --allarm --quick
+ --arm --optimizing --interpreter
+ --x86 --optimizing --interpreter
+ --allarm --optimizing
Add in --device=<device name, e.g. device:generic> if you want to specify a device.
Add in --execute-dir=<dir on device> if you want to specify an execution directory.
@@ -98,7 +97,6 @@
those occurrences.
Timed Out - mutated files that timed out for one or more backends.
Current timeouts are:
- Quick - 5 seconds
Optimizing - 5 seconds
Intepreter - 30 seconds
(use --short-timeouts to set all backends to 2 seconds.)
diff --git a/tools/dexfuzz/src/dexfuzz/Options.java b/tools/dexfuzz/src/dexfuzz/Options.java
index b442b22..7d5476d 100644
--- a/tools/dexfuzz/src/dexfuzz/Options.java
+++ b/tools/dexfuzz/src/dexfuzz/Options.java
@@ -61,7 +61,6 @@
public static boolean executeOnHost;
public static boolean noBootImage;
public static boolean useInterpreter;
- public static boolean useQuick;
public static boolean useOptimizing;
public static boolean useArchArm;
public static boolean useArchArm64;
@@ -101,7 +100,6 @@
Log.always(" --execute-class=<c> : When executing, execute this class (default: Main)");
Log.always("");
Log.always(" --interpreter : Include the Interpreter in comparisons");
- Log.always(" --quick : Include the Quick Compiler in comparisons");
Log.always(" --optimizing : Include the Optimizing Compiler in comparisons");
Log.always("");
Log.always(" --arm : Include ARM backends in comparisons");
@@ -160,8 +158,6 @@
skipHostVerify = true;
} else if (flag.equals("interpreter")) {
useInterpreter = true;
- } else if (flag.equals("quick")) {
- useQuick = true;
} else if (flag.equals("optimizing")) {
useOptimizing = true;
} else if (flag.equals("arm")) {
@@ -423,18 +419,15 @@
if (useInterpreter) {
backends++;
}
- if (useQuick) {
- backends++;
- }
if (useOptimizing) {
backends++;
}
if (useArchArm && useArchArm64) {
- // Could just be comparing quick-ARM versus quick-ARM64?
+ // Could just be comparing optimizing-ARM versus optimizing-ARM64?
backends++;
}
if (backends < 2) {
- Log.error("Not enough backends specified! Try --quick --interpreter!");
+ Log.error("Not enough backends specified! Try --optimizing --interpreter!");
return false;
}
}
diff --git a/tools/dexfuzz/src/dexfuzz/executors/Arm64OptimizingBackendExecutor.java b/tools/dexfuzz/src/dexfuzz/executors/Arm64OptimizingBackendExecutor.java
index 72e36e8..84ed4c4 100644
--- a/tools/dexfuzz/src/dexfuzz/executors/Arm64OptimizingBackendExecutor.java
+++ b/tools/dexfuzz/src/dexfuzz/executors/Arm64OptimizingBackendExecutor.java
@@ -29,6 +29,9 @@
protected String constructCommand(String programName) {
StringBuilder commandBuilder = new StringBuilder();
commandBuilder.append("dalvikvm64 -Xcompiler-option --compiler-backend=Optimizing ");
+ // The -Xno-dex-file-fallback option ensures that the execution does not default to
+ // interpreter if compilations fails.
+ commandBuilder.append("-Xno-dex-file-fallback ");
if (device.noBootImageAvailable()) {
commandBuilder.append("-Ximage:/data/art-test/core.art -Xnorelocate ");
}
diff --git a/tools/dexfuzz/src/dexfuzz/executors/Arm64QuickBackendExecutor.java b/tools/dexfuzz/src/dexfuzz/executors/Arm64QuickBackendExecutor.java
deleted file mode 100644
index d9228ed..0000000
--- a/tools/dexfuzz/src/dexfuzz/executors/Arm64QuickBackendExecutor.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (C) 2014 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.
- */
-
-package dexfuzz.executors;
-
-import dexfuzz.listeners.BaseListener;
-
-public class Arm64QuickBackendExecutor extends Executor {
-
- public Arm64QuickBackendExecutor(BaseListener listener, Device device) {
- super("ARM64 Quick Backend", 5, listener, Architecture.ARM64, device,
- /*needsCleanCodeCache*/ true, /*isBisectable*/ false);
- }
-
- @Override
- protected String constructCommand(String programName) {
- StringBuilder commandBuilder = new StringBuilder();
- commandBuilder.append("dalvikvm64 -Xcompiler-option --compiler-backend=Quick ");
- if (device.noBootImageAvailable()) {
- commandBuilder.append("-Ximage:/data/art-test/core.art -Xnorelocate ");
- }
- commandBuilder.append("-cp ").append(testLocation).append("/").append(programName).append(" ");
- commandBuilder.append(executeClass);
- return commandBuilder.toString();
- }
-}
diff --git a/tools/dexfuzz/src/dexfuzz/executors/ArmOptimizingBackendExecutor.java b/tools/dexfuzz/src/dexfuzz/executors/ArmOptimizingBackendExecutor.java
index ded8cf9..26a5eea 100644
--- a/tools/dexfuzz/src/dexfuzz/executors/ArmOptimizingBackendExecutor.java
+++ b/tools/dexfuzz/src/dexfuzz/executors/ArmOptimizingBackendExecutor.java
@@ -29,6 +29,9 @@
protected String constructCommand(String programName) {
StringBuilder commandBuilder = new StringBuilder();
commandBuilder.append("dalvikvm32 -Xcompiler-option --compiler-backend=Optimizing ");
+ // The -Xno-dex-file-fallback option ensures that the execution does not default to
+ // interpreter if compilations fails.
+ commandBuilder.append("-Xno-dex-file-fallback ");
if (device.noBootImageAvailable()) {
commandBuilder.append("-Ximage:/data/art-test/core.art -Xnorelocate ");
}
diff --git a/tools/dexfuzz/src/dexfuzz/executors/ArmQuickBackendExecutor.java b/tools/dexfuzz/src/dexfuzz/executors/ArmQuickBackendExecutor.java
deleted file mode 100644
index 0eb35f7..0000000
--- a/tools/dexfuzz/src/dexfuzz/executors/ArmQuickBackendExecutor.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (C) 2014 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.
- */
-
-package dexfuzz.executors;
-
-import dexfuzz.listeners.BaseListener;
-
-public class ArmQuickBackendExecutor extends Executor {
-
- public ArmQuickBackendExecutor(BaseListener listener, Device device) {
- super("ARM Quick Backend", 5, listener, Architecture.ARM, device,
- /*needsCleanCodeCache*/ true, /*isBisectable*/ false);
- }
-
- @Override
- protected String constructCommand(String programName) {
- StringBuilder commandBuilder = new StringBuilder();
- commandBuilder.append("dalvikvm32 -Xcompiler-option --compiler-backend=Quick ");
- if (device.noBootImageAvailable()) {
- commandBuilder.append("-Ximage:/data/art-test/core.art -Xnorelocate ");
- }
- commandBuilder.append("-cp ").append(testLocation).append("/").append(programName).append(" ");
- commandBuilder.append(executeClass);
- return commandBuilder.toString();
- }
-}
diff --git a/tools/dexfuzz/src/dexfuzz/executors/Mips64OptimizingBackendExecutor.java b/tools/dexfuzz/src/dexfuzz/executors/Mips64OptimizingBackendExecutor.java
index 72d43e7..883ff2a 100644
--- a/tools/dexfuzz/src/dexfuzz/executors/Mips64OptimizingBackendExecutor.java
+++ b/tools/dexfuzz/src/dexfuzz/executors/Mips64OptimizingBackendExecutor.java
@@ -29,6 +29,9 @@
protected String constructCommand(String programName) {
StringBuilder commandBuilder = new StringBuilder();
commandBuilder.append("dalvikvm64 -Xcompiler-option --compiler-backend=Optimizing ");
+ // The -Xno-dex-file-fallback option ensures that the execution does not default to
+ // interpreter if compilations fails.
+ commandBuilder.append("-Xno-dex-file-fallback ");
commandBuilder.append("-cp ").append(testLocation).append("/").append(programName).append(" ");
commandBuilder.append(executeClass);
return commandBuilder.toString();
diff --git a/tools/dexfuzz/src/dexfuzz/executors/Mips64QuickBackendExecutor.java b/tools/dexfuzz/src/dexfuzz/executors/Mips64QuickBackendExecutor.java
deleted file mode 100644
index e7e5ff6..0000000
--- a/tools/dexfuzz/src/dexfuzz/executors/Mips64QuickBackendExecutor.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (C) 2014 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.
- */
-
-package dexfuzz.executors;
-
-import dexfuzz.listeners.BaseListener;
-
-public class Mips64QuickBackendExecutor extends Executor {
-
- public Mips64QuickBackendExecutor(BaseListener listener, Device device) {
- super("MIPS64 Quick Backend", 5, listener, Architecture.MIPS64, device,
- /*needsCleanCodeCache*/ true, /*isBisectable*/ false);
- }
-
- @Override
- protected String constructCommand(String programName) {
- StringBuilder commandBuilder = new StringBuilder();
- commandBuilder.append("dalvikvm64 -Xcompiler-option --compiler-backend=Quick ");
- commandBuilder.append("-cp ").append(testLocation).append("/").append(programName).append(" ");
- commandBuilder.append(executeClass);
- return commandBuilder.toString();
- }
-}
diff --git a/tools/dexfuzz/src/dexfuzz/executors/MipsOptimizingBackendExecutor.java b/tools/dexfuzz/src/dexfuzz/executors/MipsOptimizingBackendExecutor.java
index 63f6858..b7babdc 100644
--- a/tools/dexfuzz/src/dexfuzz/executors/MipsOptimizingBackendExecutor.java
+++ b/tools/dexfuzz/src/dexfuzz/executors/MipsOptimizingBackendExecutor.java
@@ -29,6 +29,9 @@
protected String constructCommand(String programName) {
StringBuilder commandBuilder = new StringBuilder();
commandBuilder.append("dalvikvm32 -Xcompiler-option --compiler-backend=Optimizing ");
+ // The -Xno-dex-file-fallback option ensures that the execution does not default to
+ // interpreter if compilations fails.
+ commandBuilder.append("-Xno-dex-file-fallback ");
commandBuilder.append("-cp ").append(testLocation).append("/").append(programName).append(" ");
commandBuilder.append(executeClass);
return commandBuilder.toString();
diff --git a/tools/dexfuzz/src/dexfuzz/executors/MipsQuickBackendExecutor.java b/tools/dexfuzz/src/dexfuzz/executors/MipsQuickBackendExecutor.java
deleted file mode 100644
index b262090..0000000
--- a/tools/dexfuzz/src/dexfuzz/executors/MipsQuickBackendExecutor.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (C) 2014 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.
- */
-
-package dexfuzz.executors;
-
-import dexfuzz.listeners.BaseListener;
-
-public class MipsQuickBackendExecutor extends Executor {
-
- public MipsQuickBackendExecutor(BaseListener listener, Device device) {
- super("MIPS Quick Backend", 5, listener, Architecture.MIPS, device,
- /*needsCleanCodeCache*/ true, /*isBisectable*/ false);
- }
-
- @Override
- protected String constructCommand(String programName) {
- StringBuilder commandBuilder = new StringBuilder();
- commandBuilder.append("dalvikvm32 -Xcompiler-option --compiler-backend=Quick ");
- commandBuilder.append("-cp ").append(testLocation).append("/").append(programName).append(" ");
- commandBuilder.append(executeClass);
- return commandBuilder.toString();
- }
-}
diff --git a/tools/dexfuzz/src/dexfuzz/executors/X86OptimizingBackendExecutor.java b/tools/dexfuzz/src/dexfuzz/executors/X86OptimizingBackendExecutor.java
index 5908a8b..1d62051 100644
--- a/tools/dexfuzz/src/dexfuzz/executors/X86OptimizingBackendExecutor.java
+++ b/tools/dexfuzz/src/dexfuzz/executors/X86OptimizingBackendExecutor.java
@@ -30,6 +30,9 @@
protected String constructCommand(String programName) {
StringBuilder commandBuilder = new StringBuilder();
commandBuilder.append("dalvikvm32 -Xcompiler-option --compiler-backend=Optimizing ");
+ // The -Xno-dex-file-fallback option ensures that the execution does not default to
+ // interpreter if compilations fails.
+ commandBuilder.append("-Xno-dex-file-fallback ");
if (Options.executeOnHost) {
commandBuilder.append(device.getHostExecutionFlags()).append(" ");
}
diff --git a/tools/dexfuzz/src/dexfuzz/executors/X86QuickBackendExecutor.java b/tools/dexfuzz/src/dexfuzz/executors/X86QuickBackendExecutor.java
deleted file mode 100644
index 9e8039d..0000000
--- a/tools/dexfuzz/src/dexfuzz/executors/X86QuickBackendExecutor.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2014 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.
- */
-
-package dexfuzz.executors;
-
-import dexfuzz.Options;
-import dexfuzz.listeners.BaseListener;
-
-public class X86QuickBackendExecutor extends Executor {
-
- public X86QuickBackendExecutor(BaseListener listener, Device device) {
- super("x86 Quick Backend", 5, listener, Architecture.X86, device,
- /*needsCleanCodeCache*/ true, /*isBisectable*/ false);
- }
-
- @Override
- protected String constructCommand(String programName) {
- StringBuilder commandBuilder = new StringBuilder();
- commandBuilder.append("dalvikvm32 -Xcompiler-option --compiler-backend=Quick ");
- if (Options.executeOnHost) {
- commandBuilder.append(device.getHostExecutionFlags()).append(" ");
- }
- commandBuilder.append("-cp ").append(testLocation).append("/").append(programName).append(" ");
- commandBuilder.append(executeClass);
- return commandBuilder.toString();
- }
-}
diff --git a/tools/dexfuzz/src/dexfuzz/executors/X86_64OptimizingBackendExecutor.java b/tools/dexfuzz/src/dexfuzz/executors/X86_64OptimizingBackendExecutor.java
index 28ff1a5..ad44259 100644
--- a/tools/dexfuzz/src/dexfuzz/executors/X86_64OptimizingBackendExecutor.java
+++ b/tools/dexfuzz/src/dexfuzz/executors/X86_64OptimizingBackendExecutor.java
@@ -29,6 +29,9 @@
protected String constructCommand(String programName) {
StringBuilder commandBuilder = new StringBuilder();
commandBuilder.append("dalvikvm64 -Xcompiler-option --compiler-backend=Optimizing ");
+ // The -Xno-dex-file-fallback option ensures that the execution does not default to
+ // interpreter if compilations fails.
+ commandBuilder.append("-Xno-dex-file-fallback ");
commandBuilder.append("-cp ").append(testLocation).append("/").append(programName).append(" ");
commandBuilder.append(executeClass);
return commandBuilder.toString();
diff --git a/tools/dexfuzz/src/dexfuzz/executors/X86_64QuickBackendExecutor.java b/tools/dexfuzz/src/dexfuzz/executors/X86_64QuickBackendExecutor.java
deleted file mode 100644
index 22cafe2..0000000
--- a/tools/dexfuzz/src/dexfuzz/executors/X86_64QuickBackendExecutor.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (C) 2014 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.
- */
-
-package dexfuzz.executors;
-
-import dexfuzz.listeners.BaseListener;
-
-public class X86_64QuickBackendExecutor extends Executor {
-
- public X86_64QuickBackendExecutor(BaseListener listener, Device device) {
- super("x86_64 Quick Backend", 5, listener, Architecture.X86_64, device,
- /*needsCleanCodeCache*/ true, /*isBisectable*/ false);
- }
-
- @Override
- protected String constructCommand(String programName) {
- StringBuilder commandBuilder = new StringBuilder();
- commandBuilder.append("dalvikvm64 -Xcompiler-option --compiler-backend=Quick ");
- commandBuilder.append("-cp ").append(testLocation).append("/").append(programName).append(" ");
- commandBuilder.append(executeClass);
- return commandBuilder.toString();
- }
-}
diff --git a/tools/dexfuzz/src/dexfuzz/fuzzers/Fuzzer.java b/tools/dexfuzz/src/dexfuzz/fuzzers/Fuzzer.java
index bc39d79..1797d90 100644
--- a/tools/dexfuzz/src/dexfuzz/fuzzers/Fuzzer.java
+++ b/tools/dexfuzz/src/dexfuzz/fuzzers/Fuzzer.java
@@ -22,24 +22,18 @@
import dexfuzz.executors.Architecture;
import dexfuzz.executors.Arm64InterpreterExecutor;
import dexfuzz.executors.Arm64OptimizingBackendExecutor;
-import dexfuzz.executors.Arm64QuickBackendExecutor;
import dexfuzz.executors.ArmInterpreterExecutor;
import dexfuzz.executors.ArmOptimizingBackendExecutor;
-import dexfuzz.executors.ArmQuickBackendExecutor;
import dexfuzz.executors.Device;
import dexfuzz.executors.Executor;
import dexfuzz.executors.Mips64InterpreterExecutor;
import dexfuzz.executors.Mips64OptimizingBackendExecutor;
-import dexfuzz.executors.Mips64QuickBackendExecutor;
import dexfuzz.executors.MipsInterpreterExecutor;
import dexfuzz.executors.MipsOptimizingBackendExecutor;
-import dexfuzz.executors.MipsQuickBackendExecutor;
import dexfuzz.executors.X86InterpreterExecutor;
import dexfuzz.executors.X86OptimizingBackendExecutor;
-import dexfuzz.executors.X86QuickBackendExecutor;
import dexfuzz.executors.X86_64InterpreterExecutor;
import dexfuzz.executors.X86_64OptimizingBackendExecutor;
-import dexfuzz.executors.X86_64QuickBackendExecutor;
import dexfuzz.listeners.BaseListener;
import dexfuzz.program.Mutation;
import dexfuzz.program.Program;
@@ -121,18 +115,13 @@
}
}
- private void addExecutorsForArchitecture(Device device, Class<? extends Executor> quick,
- Class<? extends Executor> optimizing, Class<? extends Executor> interpreter) {
- // NB: Currently QuickBackend MUST come immediately before same arch's Interpreter.
+ private void addExecutorsForArchitecture(Device device, Class<? extends Executor> optimizing,
+ Class<? extends Executor> interpreter) {
+ // NB: Currently OptimizingBackend MUST come immediately before same arch's Interpreter.
// This is because intepreter execution relies on there being an OAT file already
// created to produce correct debug information. Otherwise we will see
// false-positive divergences.
try {
- if (Options.useQuick) {
- Constructor<? extends Executor> constructor =
- quick.getConstructor(BaseListener.class, Device.class);
- executors.add(constructor.newInstance(listener, device));
- }
if (Options.useOptimizing) {
Constructor<? extends Executor> constructor =
optimizing.getConstructor(BaseListener.class, Device.class);
@@ -165,33 +154,33 @@
}
if (Options.useArchArm64) {
- addExecutorsForArchitecture(device, Arm64QuickBackendExecutor.class,
- Arm64OptimizingBackendExecutor.class, Arm64InterpreterExecutor.class);
+ addExecutorsForArchitecture(device, Arm64OptimizingBackendExecutor.class,
+ Arm64InterpreterExecutor.class);
}
if (Options.useArchArm) {
- addExecutorsForArchitecture(device, ArmQuickBackendExecutor.class,
- ArmOptimizingBackendExecutor.class, ArmInterpreterExecutor.class);
+ addExecutorsForArchitecture(device, ArmOptimizingBackendExecutor.class,
+ ArmInterpreterExecutor.class);
}
if (Options.useArchX86_64) {
- addExecutorsForArchitecture(device, X86_64QuickBackendExecutor.class,
- X86_64OptimizingBackendExecutor.class, X86_64InterpreterExecutor.class);
+ addExecutorsForArchitecture(device, X86_64OptimizingBackendExecutor.class,
+ X86_64InterpreterExecutor.class);
}
if (Options.useArchX86) {
- addExecutorsForArchitecture(device, X86QuickBackendExecutor.class,
- X86OptimizingBackendExecutor.class, X86InterpreterExecutor.class);
+ addExecutorsForArchitecture(device, X86OptimizingBackendExecutor.class,
+ X86InterpreterExecutor.class);
}
if (Options.useArchMips64) {
- addExecutorsForArchitecture(device, Mips64QuickBackendExecutor.class,
- Mips64OptimizingBackendExecutor.class, Mips64InterpreterExecutor.class);
+ addExecutorsForArchitecture(device, Mips64OptimizingBackendExecutor.class,
+ Mips64InterpreterExecutor.class);
}
if (Options.useArchMips) {
- addExecutorsForArchitecture(device, MipsQuickBackendExecutor.class,
- MipsOptimizingBackendExecutor.class, MipsInterpreterExecutor.class);
+ addExecutorsForArchitecture(device, MipsOptimizingBackendExecutor.class,
+ MipsInterpreterExecutor.class);
}
// Add the first backend as the golden executor for self-divergence tests.