Merge "Integrate dexfuzz with bisection search"
diff --git a/Android.mk b/Android.mk
index 0e6f3ce..2647268 100644
--- a/Android.mk
+++ b/Android.mk
@@ -443,6 +443,8 @@
$(ART_TARGET_SHARED_LIBRARY_BENCHMARK) \
$(TARGET_CORE_IMG_OUT_BASE).art \
$(TARGET_CORE_IMG_OUT_BASE)-interpreter.art
+ sed -i '/libartd.so/d' $(TARGET_OUT)/etc/public.libraries.txt
+ # remove libartd.so from public.libraries.txt because golem builds won't have it.
########################################################################
# Phony target for building what go/lem requires on host.
diff --git a/benchmark/Android.bp b/benchmark/Android.bp
index dd19888..014a2b3 100644
--- a/benchmark/Android.bp
+++ b/benchmark/Android.bp
@@ -17,7 +17,7 @@
art_cc_library {
name: "libartbenchmark",
host_supported: true,
- defaults: ["art_defaults", "art_debug_defaults"],
+ defaults: ["art_defaults" ],
srcs: [
"jni_loader.cc",
"jobject-benchmark/jobject_benchmark.cc",
diff --git a/benchmark/const-string/info.txt b/benchmark/const-string/info.txt
new file mode 100644
index 0000000..78f39d2
--- /dev/null
+++ b/benchmark/const-string/info.txt
@@ -0,0 +1 @@
+Benchmarks for repeating const-string instructions in a loop.
diff --git a/benchmark/const-string/src/ConstStringBenchmark.java b/benchmark/const-string/src/ConstStringBenchmark.java
new file mode 100644
index 0000000..2beb0a4
--- /dev/null
+++ b/benchmark/const-string/src/ConstStringBenchmark.java
@@ -0,0 +1,1066 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+public class ConstStringBenchmark {
+ // Initialize 1025 strings with consecutive string indexes in the dex file.
+ // The tests below rely on the knowledge that ART uses the low 10 bits
+ // of the string index as the hash into DexCache strings array.
+ public static final String string_0000 = "TestString_0000";
+ public static final String string_0001 = "TestString_0001";
+ public static final String string_0002 = "TestString_0002";
+ public static final String string_0003 = "TestString_0003";
+ public static final String string_0004 = "TestString_0004";
+ public static final String string_0005 = "TestString_0005";
+ public static final String string_0006 = "TestString_0006";
+ public static final String string_0007 = "TestString_0007";
+ public static final String string_0008 = "TestString_0008";
+ public static final String string_0009 = "TestString_0009";
+ public static final String string_0010 = "TestString_0010";
+ public static final String string_0011 = "TestString_0011";
+ public static final String string_0012 = "TestString_0012";
+ public static final String string_0013 = "TestString_0013";
+ public static final String string_0014 = "TestString_0014";
+ public static final String string_0015 = "TestString_0015";
+ public static final String string_0016 = "TestString_0016";
+ public static final String string_0017 = "TestString_0017";
+ public static final String string_0018 = "TestString_0018";
+ public static final String string_0019 = "TestString_0019";
+ public static final String string_0020 = "TestString_0020";
+ public static final String string_0021 = "TestString_0021";
+ public static final String string_0022 = "TestString_0022";
+ public static final String string_0023 = "TestString_0023";
+ public static final String string_0024 = "TestString_0024";
+ public static final String string_0025 = "TestString_0025";
+ public static final String string_0026 = "TestString_0026";
+ public static final String string_0027 = "TestString_0027";
+ public static final String string_0028 = "TestString_0028";
+ public static final String string_0029 = "TestString_0029";
+ public static final String string_0030 = "TestString_0030";
+ public static final String string_0031 = "TestString_0031";
+ public static final String string_0032 = "TestString_0032";
+ public static final String string_0033 = "TestString_0033";
+ public static final String string_0034 = "TestString_0034";
+ public static final String string_0035 = "TestString_0035";
+ public static final String string_0036 = "TestString_0036";
+ public static final String string_0037 = "TestString_0037";
+ public static final String string_0038 = "TestString_0038";
+ public static final String string_0039 = "TestString_0039";
+ public static final String string_0040 = "TestString_0040";
+ public static final String string_0041 = "TestString_0041";
+ public static final String string_0042 = "TestString_0042";
+ public static final String string_0043 = "TestString_0043";
+ public static final String string_0044 = "TestString_0044";
+ public static final String string_0045 = "TestString_0045";
+ public static final String string_0046 = "TestString_0046";
+ public static final String string_0047 = "TestString_0047";
+ public static final String string_0048 = "TestString_0048";
+ public static final String string_0049 = "TestString_0049";
+ public static final String string_0050 = "TestString_0050";
+ public static final String string_0051 = "TestString_0051";
+ public static final String string_0052 = "TestString_0052";
+ public static final String string_0053 = "TestString_0053";
+ public static final String string_0054 = "TestString_0054";
+ public static final String string_0055 = "TestString_0055";
+ public static final String string_0056 = "TestString_0056";
+ public static final String string_0057 = "TestString_0057";
+ public static final String string_0058 = "TestString_0058";
+ public static final String string_0059 = "TestString_0059";
+ public static final String string_0060 = "TestString_0060";
+ public static final String string_0061 = "TestString_0061";
+ public static final String string_0062 = "TestString_0062";
+ public static final String string_0063 = "TestString_0063";
+ public static final String string_0064 = "TestString_0064";
+ public static final String string_0065 = "TestString_0065";
+ public static final String string_0066 = "TestString_0066";
+ public static final String string_0067 = "TestString_0067";
+ public static final String string_0068 = "TestString_0068";
+ public static final String string_0069 = "TestString_0069";
+ public static final String string_0070 = "TestString_0070";
+ public static final String string_0071 = "TestString_0071";
+ public static final String string_0072 = "TestString_0072";
+ public static final String string_0073 = "TestString_0073";
+ public static final String string_0074 = "TestString_0074";
+ public static final String string_0075 = "TestString_0075";
+ public static final String string_0076 = "TestString_0076";
+ public static final String string_0077 = "TestString_0077";
+ public static final String string_0078 = "TestString_0078";
+ public static final String string_0079 = "TestString_0079";
+ public static final String string_0080 = "TestString_0080";
+ public static final String string_0081 = "TestString_0081";
+ public static final String string_0082 = "TestString_0082";
+ public static final String string_0083 = "TestString_0083";
+ public static final String string_0084 = "TestString_0084";
+ public static final String string_0085 = "TestString_0085";
+ public static final String string_0086 = "TestString_0086";
+ public static final String string_0087 = "TestString_0087";
+ public static final String string_0088 = "TestString_0088";
+ public static final String string_0089 = "TestString_0089";
+ public static final String string_0090 = "TestString_0090";
+ public static final String string_0091 = "TestString_0091";
+ public static final String string_0092 = "TestString_0092";
+ public static final String string_0093 = "TestString_0093";
+ public static final String string_0094 = "TestString_0094";
+ public static final String string_0095 = "TestString_0095";
+ public static final String string_0096 = "TestString_0096";
+ public static final String string_0097 = "TestString_0097";
+ public static final String string_0098 = "TestString_0098";
+ public static final String string_0099 = "TestString_0099";
+ public static final String string_0100 = "TestString_0100";
+ public static final String string_0101 = "TestString_0101";
+ public static final String string_0102 = "TestString_0102";
+ public static final String string_0103 = "TestString_0103";
+ public static final String string_0104 = "TestString_0104";
+ public static final String string_0105 = "TestString_0105";
+ public static final String string_0106 = "TestString_0106";
+ public static final String string_0107 = "TestString_0107";
+ public static final String string_0108 = "TestString_0108";
+ public static final String string_0109 = "TestString_0109";
+ public static final String string_0110 = "TestString_0110";
+ public static final String string_0111 = "TestString_0111";
+ public static final String string_0112 = "TestString_0112";
+ public static final String string_0113 = "TestString_0113";
+ public static final String string_0114 = "TestString_0114";
+ public static final String string_0115 = "TestString_0115";
+ public static final String string_0116 = "TestString_0116";
+ public static final String string_0117 = "TestString_0117";
+ public static final String string_0118 = "TestString_0118";
+ public static final String string_0119 = "TestString_0119";
+ public static final String string_0120 = "TestString_0120";
+ public static final String string_0121 = "TestString_0121";
+ public static final String string_0122 = "TestString_0122";
+ public static final String string_0123 = "TestString_0123";
+ public static final String string_0124 = "TestString_0124";
+ public static final String string_0125 = "TestString_0125";
+ public static final String string_0126 = "TestString_0126";
+ public static final String string_0127 = "TestString_0127";
+ public static final String string_0128 = "TestString_0128";
+ public static final String string_0129 = "TestString_0129";
+ public static final String string_0130 = "TestString_0130";
+ public static final String string_0131 = "TestString_0131";
+ public static final String string_0132 = "TestString_0132";
+ public static final String string_0133 = "TestString_0133";
+ public static final String string_0134 = "TestString_0134";
+ public static final String string_0135 = "TestString_0135";
+ public static final String string_0136 = "TestString_0136";
+ public static final String string_0137 = "TestString_0137";
+ public static final String string_0138 = "TestString_0138";
+ public static final String string_0139 = "TestString_0139";
+ public static final String string_0140 = "TestString_0140";
+ public static final String string_0141 = "TestString_0141";
+ public static final String string_0142 = "TestString_0142";
+ public static final String string_0143 = "TestString_0143";
+ public static final String string_0144 = "TestString_0144";
+ public static final String string_0145 = "TestString_0145";
+ public static final String string_0146 = "TestString_0146";
+ public static final String string_0147 = "TestString_0147";
+ public static final String string_0148 = "TestString_0148";
+ public static final String string_0149 = "TestString_0149";
+ public static final String string_0150 = "TestString_0150";
+ public static final String string_0151 = "TestString_0151";
+ public static final String string_0152 = "TestString_0152";
+ public static final String string_0153 = "TestString_0153";
+ public static final String string_0154 = "TestString_0154";
+ public static final String string_0155 = "TestString_0155";
+ public static final String string_0156 = "TestString_0156";
+ public static final String string_0157 = "TestString_0157";
+ public static final String string_0158 = "TestString_0158";
+ public static final String string_0159 = "TestString_0159";
+ public static final String string_0160 = "TestString_0160";
+ public static final String string_0161 = "TestString_0161";
+ public static final String string_0162 = "TestString_0162";
+ public static final String string_0163 = "TestString_0163";
+ public static final String string_0164 = "TestString_0164";
+ public static final String string_0165 = "TestString_0165";
+ public static final String string_0166 = "TestString_0166";
+ public static final String string_0167 = "TestString_0167";
+ public static final String string_0168 = "TestString_0168";
+ public static final String string_0169 = "TestString_0169";
+ public static final String string_0170 = "TestString_0170";
+ public static final String string_0171 = "TestString_0171";
+ public static final String string_0172 = "TestString_0172";
+ public static final String string_0173 = "TestString_0173";
+ public static final String string_0174 = "TestString_0174";
+ public static final String string_0175 = "TestString_0175";
+ public static final String string_0176 = "TestString_0176";
+ public static final String string_0177 = "TestString_0177";
+ public static final String string_0178 = "TestString_0178";
+ public static final String string_0179 = "TestString_0179";
+ public static final String string_0180 = "TestString_0180";
+ public static final String string_0181 = "TestString_0181";
+ public static final String string_0182 = "TestString_0182";
+ public static final String string_0183 = "TestString_0183";
+ public static final String string_0184 = "TestString_0184";
+ public static final String string_0185 = "TestString_0185";
+ public static final String string_0186 = "TestString_0186";
+ public static final String string_0187 = "TestString_0187";
+ public static final String string_0188 = "TestString_0188";
+ public static final String string_0189 = "TestString_0189";
+ public static final String string_0190 = "TestString_0190";
+ public static final String string_0191 = "TestString_0191";
+ public static final String string_0192 = "TestString_0192";
+ public static final String string_0193 = "TestString_0193";
+ public static final String string_0194 = "TestString_0194";
+ public static final String string_0195 = "TestString_0195";
+ public static final String string_0196 = "TestString_0196";
+ public static final String string_0197 = "TestString_0197";
+ public static final String string_0198 = "TestString_0198";
+ public static final String string_0199 = "TestString_0199";
+ public static final String string_0200 = "TestString_0200";
+ public static final String string_0201 = "TestString_0201";
+ public static final String string_0202 = "TestString_0202";
+ public static final String string_0203 = "TestString_0203";
+ public static final String string_0204 = "TestString_0204";
+ public static final String string_0205 = "TestString_0205";
+ public static final String string_0206 = "TestString_0206";
+ public static final String string_0207 = "TestString_0207";
+ public static final String string_0208 = "TestString_0208";
+ public static final String string_0209 = "TestString_0209";
+ public static final String string_0210 = "TestString_0210";
+ public static final String string_0211 = "TestString_0211";
+ public static final String string_0212 = "TestString_0212";
+ public static final String string_0213 = "TestString_0213";
+ public static final String string_0214 = "TestString_0214";
+ public static final String string_0215 = "TestString_0215";
+ public static final String string_0216 = "TestString_0216";
+ public static final String string_0217 = "TestString_0217";
+ public static final String string_0218 = "TestString_0218";
+ public static final String string_0219 = "TestString_0219";
+ public static final String string_0220 = "TestString_0220";
+ public static final String string_0221 = "TestString_0221";
+ public static final String string_0222 = "TestString_0222";
+ public static final String string_0223 = "TestString_0223";
+ public static final String string_0224 = "TestString_0224";
+ public static final String string_0225 = "TestString_0225";
+ public static final String string_0226 = "TestString_0226";
+ public static final String string_0227 = "TestString_0227";
+ public static final String string_0228 = "TestString_0228";
+ public static final String string_0229 = "TestString_0229";
+ public static final String string_0230 = "TestString_0230";
+ public static final String string_0231 = "TestString_0231";
+ public static final String string_0232 = "TestString_0232";
+ public static final String string_0233 = "TestString_0233";
+ public static final String string_0234 = "TestString_0234";
+ public static final String string_0235 = "TestString_0235";
+ public static final String string_0236 = "TestString_0236";
+ public static final String string_0237 = "TestString_0237";
+ public static final String string_0238 = "TestString_0238";
+ public static final String string_0239 = "TestString_0239";
+ public static final String string_0240 = "TestString_0240";
+ public static final String string_0241 = "TestString_0241";
+ public static final String string_0242 = "TestString_0242";
+ public static final String string_0243 = "TestString_0243";
+ public static final String string_0244 = "TestString_0244";
+ public static final String string_0245 = "TestString_0245";
+ public static final String string_0246 = "TestString_0246";
+ public static final String string_0247 = "TestString_0247";
+ public static final String string_0248 = "TestString_0248";
+ public static final String string_0249 = "TestString_0249";
+ public static final String string_0250 = "TestString_0250";
+ public static final String string_0251 = "TestString_0251";
+ public static final String string_0252 = "TestString_0252";
+ public static final String string_0253 = "TestString_0253";
+ public static final String string_0254 = "TestString_0254";
+ public static final String string_0255 = "TestString_0255";
+ public static final String string_0256 = "TestString_0256";
+ public static final String string_0257 = "TestString_0257";
+ public static final String string_0258 = "TestString_0258";
+ public static final String string_0259 = "TestString_0259";
+ public static final String string_0260 = "TestString_0260";
+ public static final String string_0261 = "TestString_0261";
+ public static final String string_0262 = "TestString_0262";
+ public static final String string_0263 = "TestString_0263";
+ public static final String string_0264 = "TestString_0264";
+ public static final String string_0265 = "TestString_0265";
+ public static final String string_0266 = "TestString_0266";
+ public static final String string_0267 = "TestString_0267";
+ public static final String string_0268 = "TestString_0268";
+ public static final String string_0269 = "TestString_0269";
+ public static final String string_0270 = "TestString_0270";
+ public static final String string_0271 = "TestString_0271";
+ public static final String string_0272 = "TestString_0272";
+ public static final String string_0273 = "TestString_0273";
+ public static final String string_0274 = "TestString_0274";
+ public static final String string_0275 = "TestString_0275";
+ public static final String string_0276 = "TestString_0276";
+ public static final String string_0277 = "TestString_0277";
+ public static final String string_0278 = "TestString_0278";
+ public static final String string_0279 = "TestString_0279";
+ public static final String string_0280 = "TestString_0280";
+ public static final String string_0281 = "TestString_0281";
+ public static final String string_0282 = "TestString_0282";
+ public static final String string_0283 = "TestString_0283";
+ public static final String string_0284 = "TestString_0284";
+ public static final String string_0285 = "TestString_0285";
+ public static final String string_0286 = "TestString_0286";
+ public static final String string_0287 = "TestString_0287";
+ public static final String string_0288 = "TestString_0288";
+ public static final String string_0289 = "TestString_0289";
+ public static final String string_0290 = "TestString_0290";
+ public static final String string_0291 = "TestString_0291";
+ public static final String string_0292 = "TestString_0292";
+ public static final String string_0293 = "TestString_0293";
+ public static final String string_0294 = "TestString_0294";
+ public static final String string_0295 = "TestString_0295";
+ public static final String string_0296 = "TestString_0296";
+ public static final String string_0297 = "TestString_0297";
+ public static final String string_0298 = "TestString_0298";
+ public static final String string_0299 = "TestString_0299";
+ public static final String string_0300 = "TestString_0300";
+ public static final String string_0301 = "TestString_0301";
+ public static final String string_0302 = "TestString_0302";
+ public static final String string_0303 = "TestString_0303";
+ public static final String string_0304 = "TestString_0304";
+ public static final String string_0305 = "TestString_0305";
+ public static final String string_0306 = "TestString_0306";
+ public static final String string_0307 = "TestString_0307";
+ public static final String string_0308 = "TestString_0308";
+ public static final String string_0309 = "TestString_0309";
+ public static final String string_0310 = "TestString_0310";
+ public static final String string_0311 = "TestString_0311";
+ public static final String string_0312 = "TestString_0312";
+ public static final String string_0313 = "TestString_0313";
+ public static final String string_0314 = "TestString_0314";
+ public static final String string_0315 = "TestString_0315";
+ public static final String string_0316 = "TestString_0316";
+ public static final String string_0317 = "TestString_0317";
+ public static final String string_0318 = "TestString_0318";
+ public static final String string_0319 = "TestString_0319";
+ public static final String string_0320 = "TestString_0320";
+ public static final String string_0321 = "TestString_0321";
+ public static final String string_0322 = "TestString_0322";
+ public static final String string_0323 = "TestString_0323";
+ public static final String string_0324 = "TestString_0324";
+ public static final String string_0325 = "TestString_0325";
+ public static final String string_0326 = "TestString_0326";
+ public static final String string_0327 = "TestString_0327";
+ public static final String string_0328 = "TestString_0328";
+ public static final String string_0329 = "TestString_0329";
+ public static final String string_0330 = "TestString_0330";
+ public static final String string_0331 = "TestString_0331";
+ public static final String string_0332 = "TestString_0332";
+ public static final String string_0333 = "TestString_0333";
+ public static final String string_0334 = "TestString_0334";
+ public static final String string_0335 = "TestString_0335";
+ public static final String string_0336 = "TestString_0336";
+ public static final String string_0337 = "TestString_0337";
+ public static final String string_0338 = "TestString_0338";
+ public static final String string_0339 = "TestString_0339";
+ public static final String string_0340 = "TestString_0340";
+ public static final String string_0341 = "TestString_0341";
+ public static final String string_0342 = "TestString_0342";
+ public static final String string_0343 = "TestString_0343";
+ public static final String string_0344 = "TestString_0344";
+ public static final String string_0345 = "TestString_0345";
+ public static final String string_0346 = "TestString_0346";
+ public static final String string_0347 = "TestString_0347";
+ public static final String string_0348 = "TestString_0348";
+ public static final String string_0349 = "TestString_0349";
+ public static final String string_0350 = "TestString_0350";
+ public static final String string_0351 = "TestString_0351";
+ public static final String string_0352 = "TestString_0352";
+ public static final String string_0353 = "TestString_0353";
+ public static final String string_0354 = "TestString_0354";
+ public static final String string_0355 = "TestString_0355";
+ public static final String string_0356 = "TestString_0356";
+ public static final String string_0357 = "TestString_0357";
+ public static final String string_0358 = "TestString_0358";
+ public static final String string_0359 = "TestString_0359";
+ public static final String string_0360 = "TestString_0360";
+ public static final String string_0361 = "TestString_0361";
+ public static final String string_0362 = "TestString_0362";
+ public static final String string_0363 = "TestString_0363";
+ public static final String string_0364 = "TestString_0364";
+ public static final String string_0365 = "TestString_0365";
+ public static final String string_0366 = "TestString_0366";
+ public static final String string_0367 = "TestString_0367";
+ public static final String string_0368 = "TestString_0368";
+ public static final String string_0369 = "TestString_0369";
+ public static final String string_0370 = "TestString_0370";
+ public static final String string_0371 = "TestString_0371";
+ public static final String string_0372 = "TestString_0372";
+ public static final String string_0373 = "TestString_0373";
+ public static final String string_0374 = "TestString_0374";
+ public static final String string_0375 = "TestString_0375";
+ public static final String string_0376 = "TestString_0376";
+ public static final String string_0377 = "TestString_0377";
+ public static final String string_0378 = "TestString_0378";
+ public static final String string_0379 = "TestString_0379";
+ public static final String string_0380 = "TestString_0380";
+ public static final String string_0381 = "TestString_0381";
+ public static final String string_0382 = "TestString_0382";
+ public static final String string_0383 = "TestString_0383";
+ public static final String string_0384 = "TestString_0384";
+ public static final String string_0385 = "TestString_0385";
+ public static final String string_0386 = "TestString_0386";
+ public static final String string_0387 = "TestString_0387";
+ public static final String string_0388 = "TestString_0388";
+ public static final String string_0389 = "TestString_0389";
+ public static final String string_0390 = "TestString_0390";
+ public static final String string_0391 = "TestString_0391";
+ public static final String string_0392 = "TestString_0392";
+ public static final String string_0393 = "TestString_0393";
+ public static final String string_0394 = "TestString_0394";
+ public static final String string_0395 = "TestString_0395";
+ public static final String string_0396 = "TestString_0396";
+ public static final String string_0397 = "TestString_0397";
+ public static final String string_0398 = "TestString_0398";
+ public static final String string_0399 = "TestString_0399";
+ public static final String string_0400 = "TestString_0400";
+ public static final String string_0401 = "TestString_0401";
+ public static final String string_0402 = "TestString_0402";
+ public static final String string_0403 = "TestString_0403";
+ public static final String string_0404 = "TestString_0404";
+ public static final String string_0405 = "TestString_0405";
+ public static final String string_0406 = "TestString_0406";
+ public static final String string_0407 = "TestString_0407";
+ public static final String string_0408 = "TestString_0408";
+ public static final String string_0409 = "TestString_0409";
+ public static final String string_0410 = "TestString_0410";
+ public static final String string_0411 = "TestString_0411";
+ public static final String string_0412 = "TestString_0412";
+ public static final String string_0413 = "TestString_0413";
+ public static final String string_0414 = "TestString_0414";
+ public static final String string_0415 = "TestString_0415";
+ public static final String string_0416 = "TestString_0416";
+ public static final String string_0417 = "TestString_0417";
+ public static final String string_0418 = "TestString_0418";
+ public static final String string_0419 = "TestString_0419";
+ public static final String string_0420 = "TestString_0420";
+ public static final String string_0421 = "TestString_0421";
+ public static final String string_0422 = "TestString_0422";
+ public static final String string_0423 = "TestString_0423";
+ public static final String string_0424 = "TestString_0424";
+ public static final String string_0425 = "TestString_0425";
+ public static final String string_0426 = "TestString_0426";
+ public static final String string_0427 = "TestString_0427";
+ public static final String string_0428 = "TestString_0428";
+ public static final String string_0429 = "TestString_0429";
+ public static final String string_0430 = "TestString_0430";
+ public static final String string_0431 = "TestString_0431";
+ public static final String string_0432 = "TestString_0432";
+ public static final String string_0433 = "TestString_0433";
+ public static final String string_0434 = "TestString_0434";
+ public static final String string_0435 = "TestString_0435";
+ public static final String string_0436 = "TestString_0436";
+ public static final String string_0437 = "TestString_0437";
+ public static final String string_0438 = "TestString_0438";
+ public static final String string_0439 = "TestString_0439";
+ public static final String string_0440 = "TestString_0440";
+ public static final String string_0441 = "TestString_0441";
+ public static final String string_0442 = "TestString_0442";
+ public static final String string_0443 = "TestString_0443";
+ public static final String string_0444 = "TestString_0444";
+ public static final String string_0445 = "TestString_0445";
+ public static final String string_0446 = "TestString_0446";
+ public static final String string_0447 = "TestString_0447";
+ public static final String string_0448 = "TestString_0448";
+ public static final String string_0449 = "TestString_0449";
+ public static final String string_0450 = "TestString_0450";
+ public static final String string_0451 = "TestString_0451";
+ public static final String string_0452 = "TestString_0452";
+ public static final String string_0453 = "TestString_0453";
+ public static final String string_0454 = "TestString_0454";
+ public static final String string_0455 = "TestString_0455";
+ public static final String string_0456 = "TestString_0456";
+ public static final String string_0457 = "TestString_0457";
+ public static final String string_0458 = "TestString_0458";
+ public static final String string_0459 = "TestString_0459";
+ public static final String string_0460 = "TestString_0460";
+ public static final String string_0461 = "TestString_0461";
+ public static final String string_0462 = "TestString_0462";
+ public static final String string_0463 = "TestString_0463";
+ public static final String string_0464 = "TestString_0464";
+ public static final String string_0465 = "TestString_0465";
+ public static final String string_0466 = "TestString_0466";
+ public static final String string_0467 = "TestString_0467";
+ public static final String string_0468 = "TestString_0468";
+ public static final String string_0469 = "TestString_0469";
+ public static final String string_0470 = "TestString_0470";
+ public static final String string_0471 = "TestString_0471";
+ public static final String string_0472 = "TestString_0472";
+ public static final String string_0473 = "TestString_0473";
+ public static final String string_0474 = "TestString_0474";
+ public static final String string_0475 = "TestString_0475";
+ public static final String string_0476 = "TestString_0476";
+ public static final String string_0477 = "TestString_0477";
+ public static final String string_0478 = "TestString_0478";
+ public static final String string_0479 = "TestString_0479";
+ public static final String string_0480 = "TestString_0480";
+ public static final String string_0481 = "TestString_0481";
+ public static final String string_0482 = "TestString_0482";
+ public static final String string_0483 = "TestString_0483";
+ public static final String string_0484 = "TestString_0484";
+ public static final String string_0485 = "TestString_0485";
+ public static final String string_0486 = "TestString_0486";
+ public static final String string_0487 = "TestString_0487";
+ public static final String string_0488 = "TestString_0488";
+ public static final String string_0489 = "TestString_0489";
+ public static final String string_0490 = "TestString_0490";
+ public static final String string_0491 = "TestString_0491";
+ public static final String string_0492 = "TestString_0492";
+ public static final String string_0493 = "TestString_0493";
+ public static final String string_0494 = "TestString_0494";
+ public static final String string_0495 = "TestString_0495";
+ public static final String string_0496 = "TestString_0496";
+ public static final String string_0497 = "TestString_0497";
+ public static final String string_0498 = "TestString_0498";
+ public static final String string_0499 = "TestString_0499";
+ public static final String string_0500 = "TestString_0500";
+ public static final String string_0501 = "TestString_0501";
+ public static final String string_0502 = "TestString_0502";
+ public static final String string_0503 = "TestString_0503";
+ public static final String string_0504 = "TestString_0504";
+ public static final String string_0505 = "TestString_0505";
+ public static final String string_0506 = "TestString_0506";
+ public static final String string_0507 = "TestString_0507";
+ public static final String string_0508 = "TestString_0508";
+ public static final String string_0509 = "TestString_0509";
+ public static final String string_0510 = "TestString_0510";
+ public static final String string_0511 = "TestString_0511";
+ public static final String string_0512 = "TestString_0512";
+ public static final String string_0513 = "TestString_0513";
+ public static final String string_0514 = "TestString_0514";
+ public static final String string_0515 = "TestString_0515";
+ public static final String string_0516 = "TestString_0516";
+ public static final String string_0517 = "TestString_0517";
+ public static final String string_0518 = "TestString_0518";
+ public static final String string_0519 = "TestString_0519";
+ public static final String string_0520 = "TestString_0520";
+ public static final String string_0521 = "TestString_0521";
+ public static final String string_0522 = "TestString_0522";
+ public static final String string_0523 = "TestString_0523";
+ public static final String string_0524 = "TestString_0524";
+ public static final String string_0525 = "TestString_0525";
+ public static final String string_0526 = "TestString_0526";
+ public static final String string_0527 = "TestString_0527";
+ public static final String string_0528 = "TestString_0528";
+ public static final String string_0529 = "TestString_0529";
+ public static final String string_0530 = "TestString_0530";
+ public static final String string_0531 = "TestString_0531";
+ public static final String string_0532 = "TestString_0532";
+ public static final String string_0533 = "TestString_0533";
+ public static final String string_0534 = "TestString_0534";
+ public static final String string_0535 = "TestString_0535";
+ public static final String string_0536 = "TestString_0536";
+ public static final String string_0537 = "TestString_0537";
+ public static final String string_0538 = "TestString_0538";
+ public static final String string_0539 = "TestString_0539";
+ public static final String string_0540 = "TestString_0540";
+ public static final String string_0541 = "TestString_0541";
+ public static final String string_0542 = "TestString_0542";
+ public static final String string_0543 = "TestString_0543";
+ public static final String string_0544 = "TestString_0544";
+ public static final String string_0545 = "TestString_0545";
+ public static final String string_0546 = "TestString_0546";
+ public static final String string_0547 = "TestString_0547";
+ public static final String string_0548 = "TestString_0548";
+ public static final String string_0549 = "TestString_0549";
+ public static final String string_0550 = "TestString_0550";
+ public static final String string_0551 = "TestString_0551";
+ public static final String string_0552 = "TestString_0552";
+ public static final String string_0553 = "TestString_0553";
+ public static final String string_0554 = "TestString_0554";
+ public static final String string_0555 = "TestString_0555";
+ public static final String string_0556 = "TestString_0556";
+ public static final String string_0557 = "TestString_0557";
+ public static final String string_0558 = "TestString_0558";
+ public static final String string_0559 = "TestString_0559";
+ public static final String string_0560 = "TestString_0560";
+ public static final String string_0561 = "TestString_0561";
+ public static final String string_0562 = "TestString_0562";
+ public static final String string_0563 = "TestString_0563";
+ public static final String string_0564 = "TestString_0564";
+ public static final String string_0565 = "TestString_0565";
+ public static final String string_0566 = "TestString_0566";
+ public static final String string_0567 = "TestString_0567";
+ public static final String string_0568 = "TestString_0568";
+ public static final String string_0569 = "TestString_0569";
+ public static final String string_0570 = "TestString_0570";
+ public static final String string_0571 = "TestString_0571";
+ public static final String string_0572 = "TestString_0572";
+ public static final String string_0573 = "TestString_0573";
+ public static final String string_0574 = "TestString_0574";
+ public static final String string_0575 = "TestString_0575";
+ public static final String string_0576 = "TestString_0576";
+ public static final String string_0577 = "TestString_0577";
+ public static final String string_0578 = "TestString_0578";
+ public static final String string_0579 = "TestString_0579";
+ public static final String string_0580 = "TestString_0580";
+ public static final String string_0581 = "TestString_0581";
+ public static final String string_0582 = "TestString_0582";
+ public static final String string_0583 = "TestString_0583";
+ public static final String string_0584 = "TestString_0584";
+ public static final String string_0585 = "TestString_0585";
+ public static final String string_0586 = "TestString_0586";
+ public static final String string_0587 = "TestString_0587";
+ public static final String string_0588 = "TestString_0588";
+ public static final String string_0589 = "TestString_0589";
+ public static final String string_0590 = "TestString_0590";
+ public static final String string_0591 = "TestString_0591";
+ public static final String string_0592 = "TestString_0592";
+ public static final String string_0593 = "TestString_0593";
+ public static final String string_0594 = "TestString_0594";
+ public static final String string_0595 = "TestString_0595";
+ public static final String string_0596 = "TestString_0596";
+ public static final String string_0597 = "TestString_0597";
+ public static final String string_0598 = "TestString_0598";
+ public static final String string_0599 = "TestString_0599";
+ public static final String string_0600 = "TestString_0600";
+ public static final String string_0601 = "TestString_0601";
+ public static final String string_0602 = "TestString_0602";
+ public static final String string_0603 = "TestString_0603";
+ public static final String string_0604 = "TestString_0604";
+ public static final String string_0605 = "TestString_0605";
+ public static final String string_0606 = "TestString_0606";
+ public static final String string_0607 = "TestString_0607";
+ public static final String string_0608 = "TestString_0608";
+ public static final String string_0609 = "TestString_0609";
+ public static final String string_0610 = "TestString_0610";
+ public static final String string_0611 = "TestString_0611";
+ public static final String string_0612 = "TestString_0612";
+ public static final String string_0613 = "TestString_0613";
+ public static final String string_0614 = "TestString_0614";
+ public static final String string_0615 = "TestString_0615";
+ public static final String string_0616 = "TestString_0616";
+ public static final String string_0617 = "TestString_0617";
+ public static final String string_0618 = "TestString_0618";
+ public static final String string_0619 = "TestString_0619";
+ public static final String string_0620 = "TestString_0620";
+ public static final String string_0621 = "TestString_0621";
+ public static final String string_0622 = "TestString_0622";
+ public static final String string_0623 = "TestString_0623";
+ public static final String string_0624 = "TestString_0624";
+ public static final String string_0625 = "TestString_0625";
+ public static final String string_0626 = "TestString_0626";
+ public static final String string_0627 = "TestString_0627";
+ public static final String string_0628 = "TestString_0628";
+ public static final String string_0629 = "TestString_0629";
+ public static final String string_0630 = "TestString_0630";
+ public static final String string_0631 = "TestString_0631";
+ public static final String string_0632 = "TestString_0632";
+ public static final String string_0633 = "TestString_0633";
+ public static final String string_0634 = "TestString_0634";
+ public static final String string_0635 = "TestString_0635";
+ public static final String string_0636 = "TestString_0636";
+ public static final String string_0637 = "TestString_0637";
+ public static final String string_0638 = "TestString_0638";
+ public static final String string_0639 = "TestString_0639";
+ public static final String string_0640 = "TestString_0640";
+ public static final String string_0641 = "TestString_0641";
+ public static final String string_0642 = "TestString_0642";
+ public static final String string_0643 = "TestString_0643";
+ public static final String string_0644 = "TestString_0644";
+ public static final String string_0645 = "TestString_0645";
+ public static final String string_0646 = "TestString_0646";
+ public static final String string_0647 = "TestString_0647";
+ public static final String string_0648 = "TestString_0648";
+ public static final String string_0649 = "TestString_0649";
+ public static final String string_0650 = "TestString_0650";
+ public static final String string_0651 = "TestString_0651";
+ public static final String string_0652 = "TestString_0652";
+ public static final String string_0653 = "TestString_0653";
+ public static final String string_0654 = "TestString_0654";
+ public static final String string_0655 = "TestString_0655";
+ public static final String string_0656 = "TestString_0656";
+ public static final String string_0657 = "TestString_0657";
+ public static final String string_0658 = "TestString_0658";
+ public static final String string_0659 = "TestString_0659";
+ public static final String string_0660 = "TestString_0660";
+ public static final String string_0661 = "TestString_0661";
+ public static final String string_0662 = "TestString_0662";
+ public static final String string_0663 = "TestString_0663";
+ public static final String string_0664 = "TestString_0664";
+ public static final String string_0665 = "TestString_0665";
+ public static final String string_0666 = "TestString_0666";
+ public static final String string_0667 = "TestString_0667";
+ public static final String string_0668 = "TestString_0668";
+ public static final String string_0669 = "TestString_0669";
+ public static final String string_0670 = "TestString_0670";
+ public static final String string_0671 = "TestString_0671";
+ public static final String string_0672 = "TestString_0672";
+ public static final String string_0673 = "TestString_0673";
+ public static final String string_0674 = "TestString_0674";
+ public static final String string_0675 = "TestString_0675";
+ public static final String string_0676 = "TestString_0676";
+ public static final String string_0677 = "TestString_0677";
+ public static final String string_0678 = "TestString_0678";
+ public static final String string_0679 = "TestString_0679";
+ public static final String string_0680 = "TestString_0680";
+ public static final String string_0681 = "TestString_0681";
+ public static final String string_0682 = "TestString_0682";
+ public static final String string_0683 = "TestString_0683";
+ public static final String string_0684 = "TestString_0684";
+ public static final String string_0685 = "TestString_0685";
+ public static final String string_0686 = "TestString_0686";
+ public static final String string_0687 = "TestString_0687";
+ public static final String string_0688 = "TestString_0688";
+ public static final String string_0689 = "TestString_0689";
+ public static final String string_0690 = "TestString_0690";
+ public static final String string_0691 = "TestString_0691";
+ public static final String string_0692 = "TestString_0692";
+ public static final String string_0693 = "TestString_0693";
+ public static final String string_0694 = "TestString_0694";
+ public static final String string_0695 = "TestString_0695";
+ public static final String string_0696 = "TestString_0696";
+ public static final String string_0697 = "TestString_0697";
+ public static final String string_0698 = "TestString_0698";
+ public static final String string_0699 = "TestString_0699";
+ public static final String string_0700 = "TestString_0700";
+ public static final String string_0701 = "TestString_0701";
+ public static final String string_0702 = "TestString_0702";
+ public static final String string_0703 = "TestString_0703";
+ public static final String string_0704 = "TestString_0704";
+ public static final String string_0705 = "TestString_0705";
+ public static final String string_0706 = "TestString_0706";
+ public static final String string_0707 = "TestString_0707";
+ public static final String string_0708 = "TestString_0708";
+ public static final String string_0709 = "TestString_0709";
+ public static final String string_0710 = "TestString_0710";
+ public static final String string_0711 = "TestString_0711";
+ public static final String string_0712 = "TestString_0712";
+ public static final String string_0713 = "TestString_0713";
+ public static final String string_0714 = "TestString_0714";
+ public static final String string_0715 = "TestString_0715";
+ public static final String string_0716 = "TestString_0716";
+ public static final String string_0717 = "TestString_0717";
+ public static final String string_0718 = "TestString_0718";
+ public static final String string_0719 = "TestString_0719";
+ public static final String string_0720 = "TestString_0720";
+ public static final String string_0721 = "TestString_0721";
+ public static final String string_0722 = "TestString_0722";
+ public static final String string_0723 = "TestString_0723";
+ public static final String string_0724 = "TestString_0724";
+ public static final String string_0725 = "TestString_0725";
+ public static final String string_0726 = "TestString_0726";
+ public static final String string_0727 = "TestString_0727";
+ public static final String string_0728 = "TestString_0728";
+ public static final String string_0729 = "TestString_0729";
+ public static final String string_0730 = "TestString_0730";
+ public static final String string_0731 = "TestString_0731";
+ public static final String string_0732 = "TestString_0732";
+ public static final String string_0733 = "TestString_0733";
+ public static final String string_0734 = "TestString_0734";
+ public static final String string_0735 = "TestString_0735";
+ public static final String string_0736 = "TestString_0736";
+ public static final String string_0737 = "TestString_0737";
+ public static final String string_0738 = "TestString_0738";
+ public static final String string_0739 = "TestString_0739";
+ public static final String string_0740 = "TestString_0740";
+ public static final String string_0741 = "TestString_0741";
+ public static final String string_0742 = "TestString_0742";
+ public static final String string_0743 = "TestString_0743";
+ public static final String string_0744 = "TestString_0744";
+ public static final String string_0745 = "TestString_0745";
+ public static final String string_0746 = "TestString_0746";
+ public static final String string_0747 = "TestString_0747";
+ public static final String string_0748 = "TestString_0748";
+ public static final String string_0749 = "TestString_0749";
+ public static final String string_0750 = "TestString_0750";
+ public static final String string_0751 = "TestString_0751";
+ public static final String string_0752 = "TestString_0752";
+ public static final String string_0753 = "TestString_0753";
+ public static final String string_0754 = "TestString_0754";
+ public static final String string_0755 = "TestString_0755";
+ public static final String string_0756 = "TestString_0756";
+ public static final String string_0757 = "TestString_0757";
+ public static final String string_0758 = "TestString_0758";
+ public static final String string_0759 = "TestString_0759";
+ public static final String string_0760 = "TestString_0760";
+ public static final String string_0761 = "TestString_0761";
+ public static final String string_0762 = "TestString_0762";
+ public static final String string_0763 = "TestString_0763";
+ public static final String string_0764 = "TestString_0764";
+ public static final String string_0765 = "TestString_0765";
+ public static final String string_0766 = "TestString_0766";
+ public static final String string_0767 = "TestString_0767";
+ public static final String string_0768 = "TestString_0768";
+ public static final String string_0769 = "TestString_0769";
+ public static final String string_0770 = "TestString_0770";
+ public static final String string_0771 = "TestString_0771";
+ public static final String string_0772 = "TestString_0772";
+ public static final String string_0773 = "TestString_0773";
+ public static final String string_0774 = "TestString_0774";
+ public static final String string_0775 = "TestString_0775";
+ public static final String string_0776 = "TestString_0776";
+ public static final String string_0777 = "TestString_0777";
+ public static final String string_0778 = "TestString_0778";
+ public static final String string_0779 = "TestString_0779";
+ public static final String string_0780 = "TestString_0780";
+ public static final String string_0781 = "TestString_0781";
+ public static final String string_0782 = "TestString_0782";
+ public static final String string_0783 = "TestString_0783";
+ public static final String string_0784 = "TestString_0784";
+ public static final String string_0785 = "TestString_0785";
+ public static final String string_0786 = "TestString_0786";
+ public static final String string_0787 = "TestString_0787";
+ public static final String string_0788 = "TestString_0788";
+ public static final String string_0789 = "TestString_0789";
+ public static final String string_0790 = "TestString_0790";
+ public static final String string_0791 = "TestString_0791";
+ public static final String string_0792 = "TestString_0792";
+ public static final String string_0793 = "TestString_0793";
+ public static final String string_0794 = "TestString_0794";
+ public static final String string_0795 = "TestString_0795";
+ public static final String string_0796 = "TestString_0796";
+ public static final String string_0797 = "TestString_0797";
+ public static final String string_0798 = "TestString_0798";
+ public static final String string_0799 = "TestString_0799";
+ public static final String string_0800 = "TestString_0800";
+ public static final String string_0801 = "TestString_0801";
+ public static final String string_0802 = "TestString_0802";
+ public static final String string_0803 = "TestString_0803";
+ public static final String string_0804 = "TestString_0804";
+ public static final String string_0805 = "TestString_0805";
+ public static final String string_0806 = "TestString_0806";
+ public static final String string_0807 = "TestString_0807";
+ public static final String string_0808 = "TestString_0808";
+ public static final String string_0809 = "TestString_0809";
+ public static final String string_0810 = "TestString_0810";
+ public static final String string_0811 = "TestString_0811";
+ public static final String string_0812 = "TestString_0812";
+ public static final String string_0813 = "TestString_0813";
+ public static final String string_0814 = "TestString_0814";
+ public static final String string_0815 = "TestString_0815";
+ public static final String string_0816 = "TestString_0816";
+ public static final String string_0817 = "TestString_0817";
+ public static final String string_0818 = "TestString_0818";
+ public static final String string_0819 = "TestString_0819";
+ public static final String string_0820 = "TestString_0820";
+ public static final String string_0821 = "TestString_0821";
+ public static final String string_0822 = "TestString_0822";
+ public static final String string_0823 = "TestString_0823";
+ public static final String string_0824 = "TestString_0824";
+ public static final String string_0825 = "TestString_0825";
+ public static final String string_0826 = "TestString_0826";
+ public static final String string_0827 = "TestString_0827";
+ public static final String string_0828 = "TestString_0828";
+ public static final String string_0829 = "TestString_0829";
+ public static final String string_0830 = "TestString_0830";
+ public static final String string_0831 = "TestString_0831";
+ public static final String string_0832 = "TestString_0832";
+ public static final String string_0833 = "TestString_0833";
+ public static final String string_0834 = "TestString_0834";
+ public static final String string_0835 = "TestString_0835";
+ public static final String string_0836 = "TestString_0836";
+ public static final String string_0837 = "TestString_0837";
+ public static final String string_0838 = "TestString_0838";
+ public static final String string_0839 = "TestString_0839";
+ public static final String string_0840 = "TestString_0840";
+ public static final String string_0841 = "TestString_0841";
+ public static final String string_0842 = "TestString_0842";
+ public static final String string_0843 = "TestString_0843";
+ public static final String string_0844 = "TestString_0844";
+ public static final String string_0845 = "TestString_0845";
+ public static final String string_0846 = "TestString_0846";
+ public static final String string_0847 = "TestString_0847";
+ public static final String string_0848 = "TestString_0848";
+ public static final String string_0849 = "TestString_0849";
+ public static final String string_0850 = "TestString_0850";
+ public static final String string_0851 = "TestString_0851";
+ public static final String string_0852 = "TestString_0852";
+ public static final String string_0853 = "TestString_0853";
+ public static final String string_0854 = "TestString_0854";
+ public static final String string_0855 = "TestString_0855";
+ public static final String string_0856 = "TestString_0856";
+ public static final String string_0857 = "TestString_0857";
+ public static final String string_0858 = "TestString_0858";
+ public static final String string_0859 = "TestString_0859";
+ public static final String string_0860 = "TestString_0860";
+ public static final String string_0861 = "TestString_0861";
+ public static final String string_0862 = "TestString_0862";
+ public static final String string_0863 = "TestString_0863";
+ public static final String string_0864 = "TestString_0864";
+ public static final String string_0865 = "TestString_0865";
+ public static final String string_0866 = "TestString_0866";
+ public static final String string_0867 = "TestString_0867";
+ public static final String string_0868 = "TestString_0868";
+ public static final String string_0869 = "TestString_0869";
+ public static final String string_0870 = "TestString_0870";
+ public static final String string_0871 = "TestString_0871";
+ public static final String string_0872 = "TestString_0872";
+ public static final String string_0873 = "TestString_0873";
+ public static final String string_0874 = "TestString_0874";
+ public static final String string_0875 = "TestString_0875";
+ public static final String string_0876 = "TestString_0876";
+ public static final String string_0877 = "TestString_0877";
+ public static final String string_0878 = "TestString_0878";
+ public static final String string_0879 = "TestString_0879";
+ public static final String string_0880 = "TestString_0880";
+ public static final String string_0881 = "TestString_0881";
+ public static final String string_0882 = "TestString_0882";
+ public static final String string_0883 = "TestString_0883";
+ public static final String string_0884 = "TestString_0884";
+ public static final String string_0885 = "TestString_0885";
+ public static final String string_0886 = "TestString_0886";
+ public static final String string_0887 = "TestString_0887";
+ public static final String string_0888 = "TestString_0888";
+ public static final String string_0889 = "TestString_0889";
+ public static final String string_0890 = "TestString_0890";
+ public static final String string_0891 = "TestString_0891";
+ public static final String string_0892 = "TestString_0892";
+ public static final String string_0893 = "TestString_0893";
+ public static final String string_0894 = "TestString_0894";
+ public static final String string_0895 = "TestString_0895";
+ public static final String string_0896 = "TestString_0896";
+ public static final String string_0897 = "TestString_0897";
+ public static final String string_0898 = "TestString_0898";
+ public static final String string_0899 = "TestString_0899";
+ public static final String string_0900 = "TestString_0900";
+ public static final String string_0901 = "TestString_0901";
+ public static final String string_0902 = "TestString_0902";
+ public static final String string_0903 = "TestString_0903";
+ public static final String string_0904 = "TestString_0904";
+ public static final String string_0905 = "TestString_0905";
+ public static final String string_0906 = "TestString_0906";
+ public static final String string_0907 = "TestString_0907";
+ public static final String string_0908 = "TestString_0908";
+ public static final String string_0909 = "TestString_0909";
+ public static final String string_0910 = "TestString_0910";
+ public static final String string_0911 = "TestString_0911";
+ public static final String string_0912 = "TestString_0912";
+ public static final String string_0913 = "TestString_0913";
+ public static final String string_0914 = "TestString_0914";
+ public static final String string_0915 = "TestString_0915";
+ public static final String string_0916 = "TestString_0916";
+ public static final String string_0917 = "TestString_0917";
+ public static final String string_0918 = "TestString_0918";
+ public static final String string_0919 = "TestString_0919";
+ public static final String string_0920 = "TestString_0920";
+ public static final String string_0921 = "TestString_0921";
+ public static final String string_0922 = "TestString_0922";
+ public static final String string_0923 = "TestString_0923";
+ public static final String string_0924 = "TestString_0924";
+ public static final String string_0925 = "TestString_0925";
+ public static final String string_0926 = "TestString_0926";
+ public static final String string_0927 = "TestString_0927";
+ public static final String string_0928 = "TestString_0928";
+ public static final String string_0929 = "TestString_0929";
+ public static final String string_0930 = "TestString_0930";
+ public static final String string_0931 = "TestString_0931";
+ public static final String string_0932 = "TestString_0932";
+ public static final String string_0933 = "TestString_0933";
+ public static final String string_0934 = "TestString_0934";
+ public static final String string_0935 = "TestString_0935";
+ public static final String string_0936 = "TestString_0936";
+ public static final String string_0937 = "TestString_0937";
+ public static final String string_0938 = "TestString_0938";
+ public static final String string_0939 = "TestString_0939";
+ public static final String string_0940 = "TestString_0940";
+ public static final String string_0941 = "TestString_0941";
+ public static final String string_0942 = "TestString_0942";
+ public static final String string_0943 = "TestString_0943";
+ public static final String string_0944 = "TestString_0944";
+ public static final String string_0945 = "TestString_0945";
+ public static final String string_0946 = "TestString_0946";
+ public static final String string_0947 = "TestString_0947";
+ public static final String string_0948 = "TestString_0948";
+ public static final String string_0949 = "TestString_0949";
+ public static final String string_0950 = "TestString_0950";
+ public static final String string_0951 = "TestString_0951";
+ public static final String string_0952 = "TestString_0952";
+ public static final String string_0953 = "TestString_0953";
+ public static final String string_0954 = "TestString_0954";
+ public static final String string_0955 = "TestString_0955";
+ public static final String string_0956 = "TestString_0956";
+ public static final String string_0957 = "TestString_0957";
+ public static final String string_0958 = "TestString_0958";
+ public static final String string_0959 = "TestString_0959";
+ public static final String string_0960 = "TestString_0960";
+ public static final String string_0961 = "TestString_0961";
+ public static final String string_0962 = "TestString_0962";
+ public static final String string_0963 = "TestString_0963";
+ public static final String string_0964 = "TestString_0964";
+ public static final String string_0965 = "TestString_0965";
+ public static final String string_0966 = "TestString_0966";
+ public static final String string_0967 = "TestString_0967";
+ public static final String string_0968 = "TestString_0968";
+ public static final String string_0969 = "TestString_0969";
+ public static final String string_0970 = "TestString_0970";
+ public static final String string_0971 = "TestString_0971";
+ public static final String string_0972 = "TestString_0972";
+ public static final String string_0973 = "TestString_0973";
+ public static final String string_0974 = "TestString_0974";
+ public static final String string_0975 = "TestString_0975";
+ public static final String string_0976 = "TestString_0976";
+ public static final String string_0977 = "TestString_0977";
+ public static final String string_0978 = "TestString_0978";
+ public static final String string_0979 = "TestString_0979";
+ public static final String string_0980 = "TestString_0980";
+ public static final String string_0981 = "TestString_0981";
+ public static final String string_0982 = "TestString_0982";
+ public static final String string_0983 = "TestString_0983";
+ public static final String string_0984 = "TestString_0984";
+ public static final String string_0985 = "TestString_0985";
+ public static final String string_0986 = "TestString_0986";
+ public static final String string_0987 = "TestString_0987";
+ public static final String string_0988 = "TestString_0988";
+ public static final String string_0989 = "TestString_0989";
+ public static final String string_0990 = "TestString_0990";
+ public static final String string_0991 = "TestString_0991";
+ public static final String string_0992 = "TestString_0992";
+ public static final String string_0993 = "TestString_0993";
+ public static final String string_0994 = "TestString_0994";
+ public static final String string_0995 = "TestString_0995";
+ public static final String string_0996 = "TestString_0996";
+ public static final String string_0997 = "TestString_0997";
+ public static final String string_0998 = "TestString_0998";
+ public static final String string_0999 = "TestString_0999";
+ public static final String string_1000 = "TestString_1000";
+ public static final String string_1001 = "TestString_1001";
+ public static final String string_1002 = "TestString_1002";
+ public static final String string_1003 = "TestString_1003";
+ public static final String string_1004 = "TestString_1004";
+ public static final String string_1005 = "TestString_1005";
+ public static final String string_1006 = "TestString_1006";
+ public static final String string_1007 = "TestString_1007";
+ public static final String string_1008 = "TestString_1008";
+ public static final String string_1009 = "TestString_1009";
+ public static final String string_1010 = "TestString_1010";
+ public static final String string_1011 = "TestString_1011";
+ public static final String string_1012 = "TestString_1012";
+ public static final String string_1013 = "TestString_1013";
+ public static final String string_1014 = "TestString_1014";
+ public static final String string_1015 = "TestString_1015";
+ public static final String string_1016 = "TestString_1016";
+ public static final String string_1017 = "TestString_1017";
+ public static final String string_1018 = "TestString_1018";
+ public static final String string_1019 = "TestString_1019";
+ public static final String string_1020 = "TestString_1020";
+ public static final String string_1021 = "TestString_1021";
+ public static final String string_1022 = "TestString_1022";
+ public static final String string_1023 = "TestString_1023";
+ public static final String string_1024 = "TestString_1024";
+
+ public void timeConstStringsWithConflict(int count) {
+ for (int i = 0; i < count; ++i) {
+ $noinline$foo("TestString_0000");
+ $noinline$foo("TestString_1024");
+ }
+ }
+
+ public void timeConstStringsWithoutConflict(int count) {
+ for (int i = 0; i < count; ++i) {
+ $noinline$foo("TestString_0001");
+ $noinline$foo("TestString_1023");
+ }
+ }
+
+ static void $noinline$foo(String s) {
+ if (doThrow) { throw new Error(); }
+ }
+
+ public static boolean doThrow = false;
+}
diff --git a/benchmark/jni-perf/perf_jni.cc b/benchmark/jni-perf/perf_jni.cc
index cd8d520..06dded8 100644
--- a/benchmark/jni-perf/perf_jni.cc
+++ b/benchmark/jni-perf/perf_jni.cc
@@ -17,7 +17,7 @@
#include <assert.h>
#include "jni.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
#include "thread.h"
namespace art {
diff --git a/benchmark/jobject-benchmark/jobject_benchmark.cc b/benchmark/jobject-benchmark/jobject_benchmark.cc
index e7ca9eb..4b2c024 100644
--- a/benchmark/jobject-benchmark/jobject_benchmark.cc
+++ b/benchmark/jobject-benchmark/jobject_benchmark.cc
@@ -16,8 +16,9 @@
#include "jni.h"
+#include "java_vm_ext.h"
#include "mirror/class-inl.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
namespace art {
namespace {
@@ -25,10 +26,10 @@
extern "C" JNIEXPORT void JNICALL Java_JObjectBenchmark_timeAddRemoveLocal(
JNIEnv* env, jobject jobj, jint reps) {
ScopedObjectAccess soa(env);
- mirror::Object* obj = soa.Decode<mirror::Object*>(jobj);
+ ObjPtr<mirror::Object> obj = soa.Decode<mirror::Object>(jobj);
CHECK(obj != nullptr);
for (jint i = 0; i < reps; ++i) {
- jobject ref = soa.Env()->AddLocalReference<jobject>(obj);
+ jobject ref = soa.Env()->AddLocalReference<jobject>(obj.Decode());
soa.Env()->DeleteLocalRef(ref);
}
}
@@ -36,11 +37,11 @@
extern "C" JNIEXPORT void JNICALL Java_JObjectBenchmark_timeDecodeLocal(
JNIEnv* env, jobject jobj, jint reps) {
ScopedObjectAccess soa(env);
- mirror::Object* obj = soa.Decode<mirror::Object*>(jobj);
+ ObjPtr<mirror::Object> obj = soa.Decode<mirror::Object>(jobj);
CHECK(obj != nullptr);
- jobject ref = soa.Env()->AddLocalReference<jobject>(obj);
+ jobject ref = soa.Env()->AddLocalReference<jobject>(obj.Decode());
for (jint i = 0; i < reps; ++i) {
- CHECK_EQ(soa.Decode<mirror::Object*>(ref), obj);
+ CHECK_EQ(soa.Decode<mirror::Object>(ref), obj);
}
soa.Env()->DeleteLocalRef(ref);
}
@@ -48,7 +49,7 @@
extern "C" JNIEXPORT void JNICALL Java_JObjectBenchmark_timeAddRemoveGlobal(
JNIEnv* env, jobject jobj, jint reps) {
ScopedObjectAccess soa(env);
- mirror::Object* obj = soa.Decode<mirror::Object*>(jobj);
+ ObjPtr<mirror::Object> obj = soa.Decode<mirror::Object>(jobj);
CHECK(obj != nullptr);
for (jint i = 0; i < reps; ++i) {
jobject ref = soa.Vm()->AddGlobalRef(soa.Self(), obj);
@@ -59,11 +60,11 @@
extern "C" JNIEXPORT void JNICALL Java_JObjectBenchmark_timeDecodeGlobal(
JNIEnv* env, jobject jobj, jint reps) {
ScopedObjectAccess soa(env);
- mirror::Object* obj = soa.Decode<mirror::Object*>(jobj);
+ ObjPtr<mirror::Object> obj = soa.Decode<mirror::Object>(jobj);
CHECK(obj != nullptr);
jobject ref = soa.Vm()->AddGlobalRef(soa.Self(), obj);
for (jint i = 0; i < reps; ++i) {
- CHECK_EQ(soa.Decode<mirror::Object*>(ref), obj);
+ CHECK_EQ(soa.Decode<mirror::Object>(ref), obj);
}
soa.Vm()->DeleteGlobalRef(soa.Self(), ref);
}
@@ -71,7 +72,7 @@
extern "C" JNIEXPORT void JNICALL Java_JObjectBenchmark_timeAddRemoveWeakGlobal(
JNIEnv* env, jobject jobj, jint reps) {
ScopedObjectAccess soa(env);
- mirror::Object* obj = soa.Decode<mirror::Object*>(jobj);
+ ObjPtr<mirror::Object> obj = soa.Decode<mirror::Object>(jobj);
CHECK(obj != nullptr);
for (jint i = 0; i < reps; ++i) {
jobject ref = soa.Vm()->AddWeakGlobalRef(soa.Self(), obj);
@@ -82,11 +83,11 @@
extern "C" JNIEXPORT void JNICALL Java_JObjectBenchmark_timeDecodeWeakGlobal(
JNIEnv* env, jobject jobj, jint reps) {
ScopedObjectAccess soa(env);
- mirror::Object* obj = soa.Decode<mirror::Object*>(jobj);
+ ObjPtr<mirror::Object> obj = soa.Decode<mirror::Object>(jobj);
CHECK(obj != nullptr);
jobject ref = soa.Vm()->AddWeakGlobalRef(soa.Self(), obj);
for (jint i = 0; i < reps; ++i) {
- CHECK_EQ(soa.Decode<mirror::Object*>(ref), obj);
+ CHECK_EQ(soa.Decode<mirror::Object>(ref), obj);
}
soa.Vm()->DeleteWeakGlobalRef(soa.Self(), ref);
}
@@ -95,7 +96,7 @@
JNIEnv* env, jobject jobj, jint reps) {
ScopedObjectAccess soa(env);
for (jint i = 0; i < reps; ++i) {
- soa.Decode<mirror::Object*>(jobj);
+ soa.Decode<mirror::Object>(jobj);
}
}
diff --git a/build/art.go b/build/art.go
index 0ae6c8f..b826538 100644
--- a/build/art.go
+++ b/build/art.go
@@ -91,7 +91,7 @@
var cflags []string
deviceFrameSizeLimit := 1736
if len(ctx.AConfig().SanitizeDevice()) > 0 {
- deviceFrameSizeLimit = 6400
+ deviceFrameSizeLimit = 7400
}
cflags = append(cflags,
fmt.Sprintf("-Wframe-larger-than=%d", deviceFrameSizeLimit),
diff --git a/compiler/Android.bp b/compiler/Android.bp
index f264d30..7fb009a 100644
--- a/compiler/Android.bp
+++ b/compiler/Android.bp
@@ -31,8 +31,6 @@
"dex/verified_method.cc",
"dex/verification_results.cc",
"dex/quick_compiler_callbacks.cc",
- "dex/quick/dex_file_method_inliner.cc",
- "dex/quick/dex_file_to_method_inliner_map.cc",
"driver/compiled_method_storage.cc",
"driver/compiler_driver.cc",
"driver/compiler_options.cc",
diff --git a/compiler/common_compiler_test.cc b/compiler/common_compiler_test.cc
index 2af4d72..b726649 100644
--- a/compiler/common_compiler_test.cc
+++ b/compiler/common_compiler_test.cc
@@ -23,7 +23,6 @@
#include "class_linker.h"
#include "compiled_method.h"
#include "dex/quick_compiler_callbacks.h"
-#include "dex/quick/dex_file_to_method_inliner_map.h"
#include "dex/verification_results.h"
#include "driver/compiler_driver.h"
#include "driver/compiler_options.h"
@@ -33,7 +32,7 @@
#include "mirror/dex_cache.h"
#include "mirror/object-inl.h"
#include "oat_quick_method_header.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
#include "thread-inl.h"
#include "utils.h"
@@ -109,7 +108,8 @@
FlushInstructionCache(reinterpret_cast<char*>(base), reinterpret_cast<char*>(base + len));
}
-void CommonCompilerTest::MakeExecutable(mirror::ClassLoader* class_loader, const char* class_name) {
+void CommonCompilerTest::MakeExecutable(ObjPtr<mirror::ClassLoader> class_loader,
+ const char* class_name) {
std::string class_descriptor(DotToDescriptor(class_name));
Thread* self = Thread::Current();
StackHandleScope<1> hs(self);
@@ -176,7 +176,6 @@
size_t number_of_threads) {
compiler_driver_.reset(new CompilerDriver(compiler_options_.get(),
verification_results_.get(),
- method_inliner_map_.get(),
kind,
isa,
instruction_set_features_.get(),
@@ -200,9 +199,7 @@
compiler_options_.reset(new CompilerOptions);
verification_results_.reset(new VerificationResults(compiler_options_.get()));
- method_inliner_map_.reset(new DexFileToMethodInlinerMap);
callbacks_.reset(new QuickCompilerCallbacks(verification_results_.get(),
- method_inliner_map_.get(),
CompilerCallbacks::CallbackMode::kCompileApp));
}
@@ -223,7 +220,6 @@
timer_.reset();
compiler_driver_.reset();
callbacks_.reset();
- method_inliner_map_.reset();
verification_results_.reset();
compiler_options_.reset();
image_reservation_.reset();
diff --git a/compiler/common_compiler_test.h b/compiler/common_compiler_test.h
index 5239121..f4838c1 100644
--- a/compiler/common_compiler_test.h
+++ b/compiler/common_compiler_test.h
@@ -34,7 +34,6 @@
class CompilerDriver;
class CompilerOptions;
class CumulativeLogger;
-class DexFileToMethodInlinerMap;
class VerificationResults;
template<class T> class Handle;
@@ -51,7 +50,7 @@
static void MakeExecutable(const void* code_start, size_t code_length);
- void MakeExecutable(mirror::ClassLoader* class_loader, const char* class_name)
+ void MakeExecutable(ObjPtr<mirror::ClassLoader> class_loader, const char* class_name)
REQUIRES_SHARED(Locks::mutator_lock_);
protected:
@@ -102,7 +101,6 @@
Compiler::Kind compiler_kind_ = Compiler::kOptimizing;
std::unique_ptr<CompilerOptions> compiler_options_;
std::unique_ptr<VerificationResults> verification_results_;
- std::unique_ptr<DexFileToMethodInlinerMap> method_inliner_map_;
std::unique_ptr<CompilerDriver> compiler_driver_;
std::unique_ptr<CumulativeLogger> timer_;
std::unique_ptr<const InstructionSetFeatures> instruction_set_features_;
diff --git a/compiler/dex/dex_to_dex_compiler.cc b/compiler/dex/dex_to_dex_compiler.cc
index e0abf19..236a3b2 100644
--- a/compiler/dex/dex_to_dex_compiler.cc
+++ b/compiler/dex/dex_to_dex_compiler.cc
@@ -280,7 +280,7 @@
ScopedObjectAccess soa(Thread::Current());
StackHandleScope<1> hs(soa.Self());
Handle<mirror::ClassLoader> class_loader(hs.NewHandle(
- soa.Decode<mirror::ClassLoader*>(unit_.GetClassLoader())));
+ soa.Decode<mirror::ClassLoader>(unit_.GetClassLoader())));
ClassLinker* class_linker = unit_.GetClassLinker();
ArtMethod* resolved_method = class_linker->ResolveMethod<ClassLinker::kForceICCECheck>(
diff --git a/compiler/dex/quick/dex_file_method_inliner.cc b/compiler/dex/quick/dex_file_method_inliner.cc
deleted file mode 100644
index 6750554..0000000
--- a/compiler/dex/quick/dex_file_method_inliner.cc
+++ /dev/null
@@ -1,824 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "dex_file_method_inliner.h"
-
-#include <algorithm>
-
-#include "base/logging.h"
-#include "base/macros.h"
-#include "base/mutex-inl.h"
-#include "driver/compiler_driver.h"
-#include "thread-inl.h"
-#include "dex_instruction-inl.h"
-#include "driver/dex_compilation_unit.h"
-#include "verifier/method_verifier-inl.h"
-
-namespace art {
-
-namespace { // anonymous namespace
-
-static constexpr bool kIntrinsicIsStatic[] = {
- true, // kIntrinsicDoubleCvt
- true, // kIntrinsicFloatCvt
- true, // kIntrinsicFloat2Int
- true, // kIntrinsicDouble2Long
- true, // kIntrinsicFloatIsInfinite
- true, // kIntrinsicDoubleIsInfinite
- true, // kIntrinsicFloatIsNaN
- true, // kIntrinsicDoubleIsNaN
- true, // kIntrinsicReverseBits
- true, // kIntrinsicReverseBytes
- true, // kIntrinsicBitCount
- true, // kIntrinsicCompare,
- true, // kIntrinsicHighestOneBit
- true, // kIntrinsicLowestOneBit
- true, // kIntrinsicNumberOfLeadingZeros
- true, // kIntrinsicNumberOfTrailingZeros
- true, // kIntrinsicRotateRight
- true, // kIntrinsicRotateLeft
- true, // kIntrinsicSignum
- true, // kIntrinsicAbsInt
- true, // kIntrinsicAbsLong
- true, // kIntrinsicAbsFloat
- true, // kIntrinsicAbsDouble
- true, // kIntrinsicMinMaxInt
- true, // kIntrinsicMinMaxLong
- true, // kIntrinsicMinMaxFloat
- true, // kIntrinsicMinMaxDouble
- true, // kIntrinsicCos
- true, // kIntrinsicSin
- true, // kIntrinsicAcos
- true, // kIntrinsicAsin
- true, // kIntrinsicAtan
- true, // kIntrinsicAtan2
- true, // kIntrinsicCbrt
- true, // kIntrinsicCosh
- true, // kIntrinsicExp
- true, // kIntrinsicExpm1
- true, // kIntrinsicHypot
- true, // kIntrinsicLog
- true, // kIntrinsicLog10
- true, // kIntrinsicNextAfter
- true, // kIntrinsicSinh
- true, // kIntrinsicTan
- true, // kIntrinsicTanh
- true, // kIntrinsicSqrt
- true, // kIntrinsicCeil
- true, // kIntrinsicFloor
- true, // kIntrinsicRint
- true, // kIntrinsicRoundFloat
- true, // kIntrinsicRoundDouble
- false, // kIntrinsicReferenceGetReferent
- false, // kIntrinsicCharAt
- false, // kIntrinsicCompareTo
- false, // kIntrinsicEquals
- false, // kIntrinsicGetCharsNoCheck
- false, // kIntrinsicIsEmptyOrLength
- false, // kIntrinsicIndexOf
- true, // kIntrinsicNewStringFromBytes
- true, // kIntrinsicNewStringFromChars
- true, // kIntrinsicNewStringFromString
- true, // kIntrinsicCurrentThread
- true, // kIntrinsicPeek
- true, // kIntrinsicPoke
- false, // kIntrinsicCas
- false, // kIntrinsicUnsafeGet
- false, // kIntrinsicUnsafePut
- false, // kIntrinsicUnsafeGetAndAddInt,
- false, // kIntrinsicUnsafeGetAndAddLong,
- false, // kIntrinsicUnsafeGetAndSetInt,
- false, // kIntrinsicUnsafeGetAndSetLong,
- false, // kIntrinsicUnsafeGetAndSetObject,
- false, // kIntrinsicUnsafeLoadFence,
- false, // kIntrinsicUnsafeStoreFence,
- false, // kIntrinsicUnsafeFullFence,
- true, // kIntrinsicSystemArrayCopyCharArray
- true, // kIntrinsicSystemArrayCopy
-};
-static_assert(arraysize(kIntrinsicIsStatic) == kInlineOpNop,
- "arraysize of kIntrinsicIsStatic unexpected");
-static_assert(kIntrinsicIsStatic[kIntrinsicDoubleCvt], "DoubleCvt must be static");
-static_assert(kIntrinsicIsStatic[kIntrinsicFloatCvt], "FloatCvt must be static");
-static_assert(kIntrinsicIsStatic[kIntrinsicFloat2Int], "Float2Int must be static");
-static_assert(kIntrinsicIsStatic[kIntrinsicDouble2Long], "Double2Long must be static");
-static_assert(kIntrinsicIsStatic[kIntrinsicFloatIsInfinite], "FloatIsInfinite must be static");
-static_assert(kIntrinsicIsStatic[kIntrinsicDoubleIsInfinite], "DoubleIsInfinite must be static");
-static_assert(kIntrinsicIsStatic[kIntrinsicFloatIsNaN], "FloatIsNaN must be static");
-static_assert(kIntrinsicIsStatic[kIntrinsicDoubleIsNaN], "DoubleIsNaN must be static");
-static_assert(kIntrinsicIsStatic[kIntrinsicReverseBits], "ReverseBits must be static");
-static_assert(kIntrinsicIsStatic[kIntrinsicReverseBytes], "ReverseBytes must be static");
-static_assert(kIntrinsicIsStatic[kIntrinsicBitCount], "BitCount must be static");
-static_assert(kIntrinsicIsStatic[kIntrinsicCompare], "Compare must be static");
-static_assert(kIntrinsicIsStatic[kIntrinsicHighestOneBit], "HighestOneBit must be static");
-static_assert(kIntrinsicIsStatic[kIntrinsicLowestOneBit], "LowestOneBit must be static");
-static_assert(kIntrinsicIsStatic[kIntrinsicNumberOfLeadingZeros],
- "NumberOfLeadingZeros must be static");
-static_assert(kIntrinsicIsStatic[kIntrinsicNumberOfTrailingZeros],
- "NumberOfTrailingZeros must be static");
-static_assert(kIntrinsicIsStatic[kIntrinsicRotateRight], "RotateRight must be static");
-static_assert(kIntrinsicIsStatic[kIntrinsicRotateLeft], "RotateLeft must be static");
-static_assert(kIntrinsicIsStatic[kIntrinsicSignum], "Signum must be static");
-static_assert(kIntrinsicIsStatic[kIntrinsicAbsInt], "AbsInt must be static");
-static_assert(kIntrinsicIsStatic[kIntrinsicAbsLong], "AbsLong must be static");
-static_assert(kIntrinsicIsStatic[kIntrinsicAbsFloat], "AbsFloat must be static");
-static_assert(kIntrinsicIsStatic[kIntrinsicAbsDouble], "AbsDouble must be static");
-static_assert(kIntrinsicIsStatic[kIntrinsicMinMaxInt], "MinMaxInt must be static");
-static_assert(kIntrinsicIsStatic[kIntrinsicMinMaxLong], "MinMaxLong must be static");
-static_assert(kIntrinsicIsStatic[kIntrinsicMinMaxFloat], "MinMaxFloat must be static");
-static_assert(kIntrinsicIsStatic[kIntrinsicMinMaxDouble], "MinMaxDouble must be static");
-static_assert(kIntrinsicIsStatic[kIntrinsicCos], "Cos must be static");
-static_assert(kIntrinsicIsStatic[kIntrinsicSin], "Sin must be static");
-static_assert(kIntrinsicIsStatic[kIntrinsicAcos], "Acos must be static");
-static_assert(kIntrinsicIsStatic[kIntrinsicAsin], "Asin must be static");
-static_assert(kIntrinsicIsStatic[kIntrinsicAtan], "Atan must be static");
-static_assert(kIntrinsicIsStatic[kIntrinsicAtan2], "Atan2 must be static");
-static_assert(kIntrinsicIsStatic[kIntrinsicCbrt], "Cbrt must be static");
-static_assert(kIntrinsicIsStatic[kIntrinsicCosh], "Cosh must be static");
-static_assert(kIntrinsicIsStatic[kIntrinsicExp], "Exp must be static");
-static_assert(kIntrinsicIsStatic[kIntrinsicExpm1], "Expm1 must be static");
-static_assert(kIntrinsicIsStatic[kIntrinsicHypot], "Hypot must be static");
-static_assert(kIntrinsicIsStatic[kIntrinsicLog], "Log must be static");
-static_assert(kIntrinsicIsStatic[kIntrinsicLog10], "Log10 must be static");
-static_assert(kIntrinsicIsStatic[kIntrinsicNextAfter], "NextAfter must be static");
-static_assert(kIntrinsicIsStatic[kIntrinsicSinh], "Sinh must be static");
-static_assert(kIntrinsicIsStatic[kIntrinsicTan], "Tan must be static");
-static_assert(kIntrinsicIsStatic[kIntrinsicTanh], "Tanh must be static");
-static_assert(kIntrinsicIsStatic[kIntrinsicSqrt], "Sqrt must be static");
-static_assert(kIntrinsicIsStatic[kIntrinsicCeil], "Ceil must be static");
-static_assert(kIntrinsicIsStatic[kIntrinsicFloor], "Floor must be static");
-static_assert(kIntrinsicIsStatic[kIntrinsicRint], "Rint must be static");
-static_assert(kIntrinsicIsStatic[kIntrinsicRoundFloat], "RoundFloat must be static");
-static_assert(kIntrinsicIsStatic[kIntrinsicRoundDouble], "RoundDouble must be static");
-static_assert(!kIntrinsicIsStatic[kIntrinsicReferenceGetReferent], "Get must not be static");
-static_assert(!kIntrinsicIsStatic[kIntrinsicCharAt], "CharAt must not be static");
-static_assert(!kIntrinsicIsStatic[kIntrinsicCompareTo], "CompareTo must not be static");
-static_assert(!kIntrinsicIsStatic[kIntrinsicEquals], "String equals must not be static");
-static_assert(!kIntrinsicIsStatic[kIntrinsicGetCharsNoCheck], "GetCharsNoCheck must not be static");
-static_assert(!kIntrinsicIsStatic[kIntrinsicIsEmptyOrLength], "IsEmptyOrLength must not be static");
-static_assert(!kIntrinsicIsStatic[kIntrinsicIndexOf], "IndexOf must not be static");
-static_assert(kIntrinsicIsStatic[kIntrinsicNewStringFromBytes],
- "NewStringFromBytes must be static");
-static_assert(kIntrinsicIsStatic[kIntrinsicNewStringFromChars],
- "NewStringFromChars must be static");
-static_assert(kIntrinsicIsStatic[kIntrinsicNewStringFromString],
- "NewStringFromString must be static");
-static_assert(kIntrinsicIsStatic[kIntrinsicCurrentThread], "CurrentThread must be static");
-static_assert(kIntrinsicIsStatic[kIntrinsicPeek], "Peek must be static");
-static_assert(kIntrinsicIsStatic[kIntrinsicPoke], "Poke must be static");
-static_assert(!kIntrinsicIsStatic[kIntrinsicCas], "Cas must not be static");
-static_assert(!kIntrinsicIsStatic[kIntrinsicUnsafeGet], "UnsafeGet must not be static");
-static_assert(!kIntrinsicIsStatic[kIntrinsicUnsafePut], "UnsafePut must not be static");
-static_assert(!kIntrinsicIsStatic[kIntrinsicUnsafeGetAndAddInt], "UnsafeGetAndAddInt must not be static");
-static_assert(!kIntrinsicIsStatic[kIntrinsicUnsafeGetAndAddLong], "UnsafeGetAndAddLong must not be static");
-static_assert(!kIntrinsicIsStatic[kIntrinsicUnsafeGetAndSetInt], "UnsafeGetAndSetInt must not be static");
-static_assert(!kIntrinsicIsStatic[kIntrinsicUnsafeGetAndSetLong], "UnsafeGetAndSetLong must not be static");
-static_assert(!kIntrinsicIsStatic[kIntrinsicUnsafeGetAndSetObject], "UnsafeGetAndSetObject must not be static");
-static_assert(!kIntrinsicIsStatic[kIntrinsicUnsafeLoadFence], "UnsafeLoadFence must not be static");
-static_assert(!kIntrinsicIsStatic[kIntrinsicUnsafeStoreFence], "UnsafeStoreFence must not be static");
-static_assert(!kIntrinsicIsStatic[kIntrinsicUnsafeFullFence], "UnsafeFullFence must not be static");
-static_assert(kIntrinsicIsStatic[kIntrinsicSystemArrayCopyCharArray],
- "SystemArrayCopyCharArray must be static");
-static_assert(kIntrinsicIsStatic[kIntrinsicSystemArrayCopy],
- "SystemArrayCopy must be static");
-
-} // anonymous namespace
-
-const uint32_t DexFileMethodInliner::kIndexUnresolved;
-const char* const DexFileMethodInliner::kClassCacheNames[] = {
- "Z", // kClassCacheBoolean
- "B", // kClassCacheByte
- "C", // kClassCacheChar
- "S", // kClassCacheShort
- "I", // kClassCacheInt
- "J", // kClassCacheLong
- "F", // kClassCacheFloat
- "D", // kClassCacheDouble
- "V", // kClassCacheVoid
- "[B", // kClassCacheJavaLangByteArray
- "[C", // kClassCacheJavaLangCharArray
- "[I", // kClassCacheJavaLangIntArray
- "Ljava/lang/Object;", // kClassCacheJavaLangObject
- "Ljava/lang/ref/Reference;", // kClassCacheJavaLangRefReference
- "Ljava/lang/String;", // kClassCacheJavaLangString
- "Ljava/lang/StringBuffer;", // kClassCacheJavaLangStringBuffer
- "Ljava/lang/StringBuilder;", // kClassCacheJavaLangStringBuilder
- "Ljava/lang/StringFactory;", // kClassCacheJavaLangStringFactory
- "Ljava/lang/Double;", // kClassCacheJavaLangDouble
- "Ljava/lang/Float;", // kClassCacheJavaLangFloat
- "Ljava/lang/Integer;", // kClassCacheJavaLangInteger
- "Ljava/lang/Long;", // kClassCacheJavaLangLong
- "Ljava/lang/Short;", // kClassCacheJavaLangShort
- "Ljava/lang/Math;", // kClassCacheJavaLangMath
- "Ljava/lang/StrictMath;", // kClassCacheJavaLangStrictMath
- "Ljava/lang/Thread;", // kClassCacheJavaLangThread
- "Ljava/nio/charset/Charset;", // kClassCacheJavaNioCharsetCharset
- "Llibcore/io/Memory;", // kClassCacheLibcoreIoMemory
- "Lsun/misc/Unsafe;", // kClassCacheSunMiscUnsafe
- "Ljava/lang/System;", // kClassCacheJavaLangSystem
-};
-
-const char* const DexFileMethodInliner::kNameCacheNames[] = {
- "reverse", // kNameCacheReverse
- "reverseBytes", // kNameCacheReverseBytes
- "doubleToRawLongBits", // kNameCacheDoubleToRawLongBits
- "longBitsToDouble", // kNameCacheLongBitsToDouble
- "floatToRawIntBits", // kNameCacheFloatToRawIntBits
- "intBitsToFloat", // kNameCacheIntBitsToFloat
- "abs", // kNameCacheAbs
- "max", // kNameCacheMax
- "min", // kNameCacheMin
- "cos", // kNameCacheCos
- "sin", // kNameCacheSin
- "acos", // kNameCacheAcos
- "asin", // kNameCacheAsin
- "atan", // kNameCacheAtan
- "atan2", // kNameCacheAtan2
- "cbrt", // kNameCacheCbrt
- "cosh", // kNameCacheCosh
- "exp", // kNameCacheExp
- "expm1", // kNameCacheExpm1
- "hypot", // kNameCacheHypot
- "log", // kNameCacheLog
- "log10", // kNameCacheLog10
- "nextAfter", // kNameCacheNextAfter
- "sinh", // kNameCacheSinh
- "tan", // kNameCacheTan
- "tanh", // kNameCacheTanh
- "sqrt", // kNameCacheSqrt
- "ceil", // kNameCacheCeil
- "floor", // kNameCacheFloor
- "rint", // kNameCacheRint
- "round", // kNameCacheRound
- "getReferent", // kNameCacheReferenceGet
- "charAt", // kNameCacheCharAt
- "compareTo", // kNameCacheCompareTo
- "equals", // kNameCacheEquals
- "getCharsNoCheck", // kNameCacheGetCharsNoCheck
- "isEmpty", // kNameCacheIsEmpty
- "floatToIntBits", // kNameCacheFloatToIntBits
- "doubleToLongBits", // kNameCacheDoubleToLongBits
- "isInfinite", // kNameCacheIsInfinite
- "isNaN", // kNameCacheIsNaN
- "indexOf", // kNameCacheIndexOf
- "length", // kNameCacheLength
- "<init>", // kNameCacheInit
- "newStringFromBytes", // kNameCacheNewStringFromBytes
- "newStringFromChars", // kNameCacheNewStringFromChars
- "newStringFromString", // kNameCacheNewStringFromString
- "currentThread", // kNameCacheCurrentThread
- "peekByte", // kNameCachePeekByte
- "peekIntNative", // kNameCachePeekIntNative
- "peekLongNative", // kNameCachePeekLongNative
- "peekShortNative", // kNameCachePeekShortNative
- "pokeByte", // kNameCachePokeByte
- "pokeIntNative", // kNameCachePokeIntNative
- "pokeLongNative", // kNameCachePokeLongNative
- "pokeShortNative", // kNameCachePokeShortNative
- "compareAndSwapInt", // kNameCacheCompareAndSwapInt
- "compareAndSwapLong", // kNameCacheCompareAndSwapLong
- "compareAndSwapObject", // kNameCacheCompareAndSwapObject
- "getInt", // kNameCacheGetInt
- "getIntVolatile", // kNameCacheGetIntVolatile
- "putInt", // kNameCachePutInt
- "putIntVolatile", // kNameCachePutIntVolatile
- "putOrderedInt", // kNameCachePutOrderedInt
- "getLong", // kNameCacheGetLong
- "getLongVolatile", // kNameCacheGetLongVolatile
- "putLong", // kNameCachePutLong
- "putLongVolatile", // kNameCachePutLongVolatile
- "putOrderedLong", // kNameCachePutOrderedLong
- "getObject", // kNameCacheGetObject
- "getObjectVolatile", // kNameCacheGetObjectVolatile
- "putObject", // kNameCachePutObject
- "putObjectVolatile", // kNameCachePutObjectVolatile
- "putOrderedObject", // kNameCachePutOrderedObject
- "getAndAddInt", // kNameCacheGetAndAddInt,
- "getAndAddLong", // kNameCacheGetAndAddLong,
- "getAndSetInt", // kNameCacheGetAndSetInt,
- "getAndSetLong", // kNameCacheGetAndSetLong,
- "getAndSetObject", // kNameCacheGetAndSetObject,
- "loadFence", // kNameCacheLoadFence,
- "storeFence", // kNameCacheStoreFence,
- "fullFence", // kNameCacheFullFence,
- "arraycopy", // kNameCacheArrayCopy
- "bitCount", // kNameCacheBitCount
- "compare", // kNameCacheCompare
- "highestOneBit", // kNameCacheHighestOneBit
- "lowestOneBit", // kNameCacheLowestOneBit
- "numberOfLeadingZeros", // kNameCacheNumberOfLeadingZeros
- "numberOfTrailingZeros", // kNameCacheNumberOfTrailingZeros
- "rotateRight", // kNameCacheRotateRight
- "rotateLeft", // kNameCacheRotateLeft
- "signum", // kNameCacheSignum
-};
-
-const DexFileMethodInliner::ProtoDef DexFileMethodInliner::kProtoCacheDefs[] = {
- // kProtoCacheI_I
- { kClassCacheInt, 1, { kClassCacheInt } },
- // kProtoCacheJ_J
- { kClassCacheLong, 1, { kClassCacheLong } },
- // kProtoCacheS_S
- { kClassCacheShort, 1, { kClassCacheShort } },
- // kProtoCacheD_D
- { kClassCacheDouble, 1, { kClassCacheDouble } },
- // kProtoCacheDD_D
- { kClassCacheDouble, 2, { kClassCacheDouble, kClassCacheDouble } },
- // kProtoCacheF_F
- { kClassCacheFloat, 1, { kClassCacheFloat } },
- // kProtoCacheFF_F
- { kClassCacheFloat, 2, { kClassCacheFloat, kClassCacheFloat } },
- // kProtoCacheD_J
- { kClassCacheLong, 1, { kClassCacheDouble } },
- // kProtoCacheD_Z
- { kClassCacheBoolean, 1, { kClassCacheDouble } },
- // kProtoCacheJ_D
- { kClassCacheDouble, 1, { kClassCacheLong } },
- // kProtoCacheF_I
- { kClassCacheInt, 1, { kClassCacheFloat } },
- // kProtoCacheF_Z
- { kClassCacheBoolean, 1, { kClassCacheFloat } },
- // kProtoCacheI_F
- { kClassCacheFloat, 1, { kClassCacheInt } },
- // kProtoCacheII_I
- { kClassCacheInt, 2, { kClassCacheInt, kClassCacheInt } },
- // kProtoCacheI_C
- { kClassCacheChar, 1, { kClassCacheInt } },
- // kProtoCacheString_I
- { kClassCacheInt, 1, { kClassCacheJavaLangString } },
- // kProtoCache_Z
- { kClassCacheBoolean, 0, { } },
- // kProtoCache_I
- { kClassCacheInt, 0, { } },
- // kProtoCache_Object
- { kClassCacheJavaLangObject, 0, { } },
- // kProtoCache_Thread
- { kClassCacheJavaLangThread, 0, { } },
- // kProtoCacheJ_B
- { kClassCacheByte, 1, { kClassCacheLong } },
- // kProtoCacheJ_I
- { kClassCacheInt, 1, { kClassCacheLong } },
- // kProtoCacheJ_S
- { kClassCacheShort, 1, { kClassCacheLong } },
- // kProtoCacheJB_V
- { kClassCacheVoid, 2, { kClassCacheLong, kClassCacheByte } },
- // kProtoCacheJI_V
- { kClassCacheVoid, 2, { kClassCacheLong, kClassCacheInt } },
- // kProtoCacheJJ_J
- { kClassCacheLong, 2, { kClassCacheLong, kClassCacheLong } },
- // kProtoCacheJJ_I
- { kClassCacheInt, 2, { kClassCacheLong, kClassCacheLong } },
- // kProtoCacheJJ_V
- { kClassCacheVoid, 2, { kClassCacheLong, kClassCacheLong } },
- // kProtoCacheJS_V
- { kClassCacheVoid, 2, { kClassCacheLong, kClassCacheShort } },
- // kProtoCacheObject_Z
- { kClassCacheBoolean, 1, { kClassCacheJavaLangObject } },
- // kProtoCacheJI_J
- { kClassCacheLong, 2, { kClassCacheLong, kClassCacheInt } },
- // kProtoCacheObjectJII_Z
- { kClassCacheBoolean, 4, { kClassCacheJavaLangObject, kClassCacheLong,
- kClassCacheInt, kClassCacheInt } },
- // kProtoCacheObjectJJJ_Z
- { kClassCacheBoolean, 4, { kClassCacheJavaLangObject, kClassCacheLong,
- kClassCacheLong, kClassCacheLong } },
- // kProtoCacheObjectJObjectObject_Z
- { kClassCacheBoolean, 4, { kClassCacheJavaLangObject, kClassCacheLong,
- kClassCacheJavaLangObject, kClassCacheJavaLangObject } },
- // kProtoCacheObjectJ_I
- { kClassCacheInt, 2, { kClassCacheJavaLangObject, kClassCacheLong } },
- // kProtoCacheObjectJI_I
- { kClassCacheInt, 3, { kClassCacheJavaLangObject, kClassCacheLong, kClassCacheInt } },
- // kProtoCacheObjectJI_V
- { kClassCacheVoid, 3, { kClassCacheJavaLangObject, kClassCacheLong, kClassCacheInt } },
- // kProtoCacheObjectJ_J
- { kClassCacheLong, 2, { kClassCacheJavaLangObject, kClassCacheLong } },
- // kProtoCacheObjectJJ_J
- { kClassCacheLong, 3, { kClassCacheJavaLangObject, kClassCacheLong, kClassCacheLong } },
- // kProtoCacheObjectJJ_V
- { kClassCacheVoid, 3, { kClassCacheJavaLangObject, kClassCacheLong, kClassCacheLong } },
- // kProtoCacheObjectJ_Object
- { kClassCacheJavaLangObject, 2, { kClassCacheJavaLangObject, kClassCacheLong } },
- // kProtoCacheObjectJObject_V
- { kClassCacheVoid, 3, { kClassCacheJavaLangObject, kClassCacheLong,
- kClassCacheJavaLangObject } },
- // kProtoCacheObjectJObject_Object
- { kClassCacheJavaLangObject, 3, { kClassCacheJavaLangObject, kClassCacheLong,
- kClassCacheJavaLangObject } },
- // kProtoCacheCharArrayICharArrayII_V
- { kClassCacheVoid, 5, {kClassCacheJavaLangCharArray, kClassCacheInt,
- kClassCacheJavaLangCharArray, kClassCacheInt, kClassCacheInt} },
- // kProtoCacheObjectIObjectII_V
- { kClassCacheVoid, 5, {kClassCacheJavaLangObject, kClassCacheInt,
- kClassCacheJavaLangObject, kClassCacheInt, kClassCacheInt} },
- // kProtoCacheIICharArrayI_V
- { kClassCacheVoid, 4, { kClassCacheInt, kClassCacheInt, kClassCacheJavaLangCharArray,
- kClassCacheInt } },
- // kProtoCacheByteArrayIII_String
- { kClassCacheJavaLangString, 4, { kClassCacheJavaLangByteArray, kClassCacheInt, kClassCacheInt,
- kClassCacheInt } },
- // kProtoCacheIICharArray_String
- { kClassCacheJavaLangString, 3, { kClassCacheInt, kClassCacheInt,
- kClassCacheJavaLangCharArray } },
- // kProtoCacheString_String
- { kClassCacheJavaLangString, 1, { kClassCacheJavaLangString } },
- // kProtoCache_V
- { kClassCacheVoid, 0, { } },
- // kProtoCacheByteArray_V
- { kClassCacheVoid, 1, { kClassCacheJavaLangByteArray } },
- // kProtoCacheByteArrayI_V
- { kClassCacheVoid, 2, { kClassCacheJavaLangByteArray, kClassCacheInt } },
- // kProtoCacheByteArrayII_V
- { kClassCacheVoid, 3, { kClassCacheJavaLangByteArray, kClassCacheInt, kClassCacheInt } },
- // kProtoCacheByteArrayIII_V
- { kClassCacheVoid, 4, { kClassCacheJavaLangByteArray, kClassCacheInt, kClassCacheInt,
- kClassCacheInt } },
- // kProtoCacheByteArrayIIString_V
- { kClassCacheVoid, 4, { kClassCacheJavaLangByteArray, kClassCacheInt, kClassCacheInt,
- kClassCacheJavaLangString } },
- // kProtoCacheByteArrayString_V
- { kClassCacheVoid, 2, { kClassCacheJavaLangByteArray, kClassCacheJavaLangString } },
- // kProtoCacheByteArrayIICharset_V
- { kClassCacheVoid, 4, { kClassCacheJavaLangByteArray, kClassCacheInt, kClassCacheInt,
- kClassCacheJavaNioCharsetCharset } },
- // kProtoCacheByteArrayCharset_V
- { kClassCacheVoid, 2, { kClassCacheJavaLangByteArray, kClassCacheJavaNioCharsetCharset } },
- // kProtoCacheCharArray_V
- { kClassCacheVoid, 1, { kClassCacheJavaLangCharArray } },
- // kProtoCacheCharArrayII_V
- { kClassCacheVoid, 3, { kClassCacheJavaLangCharArray, kClassCacheInt, kClassCacheInt } },
- // kProtoCacheIICharArray_V
- { kClassCacheVoid, 3, { kClassCacheInt, kClassCacheInt, kClassCacheJavaLangCharArray } },
- // kProtoCacheIntArrayII_V
- { kClassCacheVoid, 3, { kClassCacheJavaLangIntArray, kClassCacheInt, kClassCacheInt } },
- // kProtoCacheString_V
- { kClassCacheVoid, 1, { kClassCacheJavaLangString } },
- // kProtoCacheStringBuffer_V
- { kClassCacheVoid, 1, { kClassCacheJavaLangStringBuffer } },
- // kProtoCacheStringBuilder_V
- { kClassCacheVoid, 1, { kClassCacheJavaLangStringBuilder } },
-};
-
-const DexFileMethodInliner::IntrinsicDef DexFileMethodInliner::kIntrinsicMethods[] = {
-#define INTRINSIC(c, n, p, o, d) \
- { { kClassCache ## c, kNameCache ## n, kProtoCache ## p }, { o, kInlineIntrinsic, { d } } }
-
- INTRINSIC(JavaLangDouble, DoubleToRawLongBits, D_J, kIntrinsicDoubleCvt, 0),
- INTRINSIC(JavaLangDouble, LongBitsToDouble, J_D, kIntrinsicDoubleCvt, kIntrinsicFlagToFloatingPoint),
- INTRINSIC(JavaLangFloat, FloatToRawIntBits, F_I, kIntrinsicFloatCvt, 0),
- INTRINSIC(JavaLangFloat, IntBitsToFloat, I_F, kIntrinsicFloatCvt, kIntrinsicFlagToFloatingPoint),
-
- INTRINSIC(JavaLangFloat, FloatToIntBits, F_I, kIntrinsicFloat2Int, 0),
- INTRINSIC(JavaLangDouble, DoubleToLongBits, D_J, kIntrinsicDouble2Long, 0),
-
- INTRINSIC(JavaLangFloat, IsInfinite, F_Z, kIntrinsicFloatIsInfinite, 0),
- INTRINSIC(JavaLangDouble, IsInfinite, D_Z, kIntrinsicDoubleIsInfinite, 0),
- INTRINSIC(JavaLangFloat, IsNaN, F_Z, kIntrinsicFloatIsNaN, 0),
- INTRINSIC(JavaLangDouble, IsNaN, D_Z, kIntrinsicDoubleIsNaN, 0),
-
- INTRINSIC(JavaLangInteger, ReverseBytes, I_I, kIntrinsicReverseBytes, k32),
- INTRINSIC(JavaLangLong, ReverseBytes, J_J, kIntrinsicReverseBytes, k64),
- INTRINSIC(JavaLangShort, ReverseBytes, S_S, kIntrinsicReverseBytes, kSignedHalf),
- INTRINSIC(JavaLangInteger, Reverse, I_I, kIntrinsicReverseBits, k32),
- INTRINSIC(JavaLangLong, Reverse, J_J, kIntrinsicReverseBits, k64),
-
- INTRINSIC(JavaLangInteger, BitCount, I_I, kIntrinsicBitCount, k32),
- INTRINSIC(JavaLangLong, BitCount, J_I, kIntrinsicBitCount, k64),
- INTRINSIC(JavaLangInteger, Compare, II_I, kIntrinsicCompare, k32),
- INTRINSIC(JavaLangLong, Compare, JJ_I, kIntrinsicCompare, k64),
- INTRINSIC(JavaLangInteger, HighestOneBit, I_I, kIntrinsicHighestOneBit, k32),
- INTRINSIC(JavaLangLong, HighestOneBit, J_J, kIntrinsicHighestOneBit, k64),
- INTRINSIC(JavaLangInteger, LowestOneBit, I_I, kIntrinsicLowestOneBit, k32),
- INTRINSIC(JavaLangLong, LowestOneBit, J_J, kIntrinsicLowestOneBit, k64),
- INTRINSIC(JavaLangInteger, NumberOfLeadingZeros, I_I, kIntrinsicNumberOfLeadingZeros, k32),
- INTRINSIC(JavaLangLong, NumberOfLeadingZeros, J_I, kIntrinsicNumberOfLeadingZeros, k64),
- INTRINSIC(JavaLangInteger, NumberOfTrailingZeros, I_I, kIntrinsicNumberOfTrailingZeros, k32),
- INTRINSIC(JavaLangLong, NumberOfTrailingZeros, J_I, kIntrinsicNumberOfTrailingZeros, k64),
- INTRINSIC(JavaLangInteger, Signum, I_I, kIntrinsicSignum, k32),
- INTRINSIC(JavaLangLong, Signum, J_I, kIntrinsicSignum, k64),
-
- INTRINSIC(JavaLangMath, Abs, I_I, kIntrinsicAbsInt, 0),
- INTRINSIC(JavaLangStrictMath, Abs, I_I, kIntrinsicAbsInt, 0),
- INTRINSIC(JavaLangMath, Abs, J_J, kIntrinsicAbsLong, 0),
- INTRINSIC(JavaLangStrictMath, Abs, J_J, kIntrinsicAbsLong, 0),
- INTRINSIC(JavaLangMath, Abs, F_F, kIntrinsicAbsFloat, 0),
- INTRINSIC(JavaLangStrictMath, Abs, F_F, kIntrinsicAbsFloat, 0),
- INTRINSIC(JavaLangMath, Abs, D_D, kIntrinsicAbsDouble, 0),
- INTRINSIC(JavaLangStrictMath, Abs, D_D, kIntrinsicAbsDouble, 0),
- INTRINSIC(JavaLangMath, Min, II_I, kIntrinsicMinMaxInt, kIntrinsicFlagMin),
- INTRINSIC(JavaLangStrictMath, Min, II_I, kIntrinsicMinMaxInt, kIntrinsicFlagMin),
- INTRINSIC(JavaLangMath, Max, II_I, kIntrinsicMinMaxInt, kIntrinsicFlagMax),
- INTRINSIC(JavaLangStrictMath, Max, II_I, kIntrinsicMinMaxInt, kIntrinsicFlagMax),
- INTRINSIC(JavaLangMath, Min, JJ_J, kIntrinsicMinMaxLong, kIntrinsicFlagMin),
- INTRINSIC(JavaLangStrictMath, Min, JJ_J, kIntrinsicMinMaxLong, kIntrinsicFlagMin),
- INTRINSIC(JavaLangMath, Max, JJ_J, kIntrinsicMinMaxLong, kIntrinsicFlagMax),
- INTRINSIC(JavaLangStrictMath, Max, JJ_J, kIntrinsicMinMaxLong, kIntrinsicFlagMax),
- INTRINSIC(JavaLangMath, Min, FF_F, kIntrinsicMinMaxFloat, kIntrinsicFlagMin),
- INTRINSIC(JavaLangStrictMath, Min, FF_F, kIntrinsicMinMaxFloat, kIntrinsicFlagMin),
- INTRINSIC(JavaLangMath, Max, FF_F, kIntrinsicMinMaxFloat, kIntrinsicFlagMax),
- INTRINSIC(JavaLangStrictMath, Max, FF_F, kIntrinsicMinMaxFloat, kIntrinsicFlagMax),
- INTRINSIC(JavaLangMath, Min, DD_D, kIntrinsicMinMaxDouble, kIntrinsicFlagMin),
- INTRINSIC(JavaLangStrictMath, Min, DD_D, kIntrinsicMinMaxDouble, kIntrinsicFlagMin),
- INTRINSIC(JavaLangMath, Max, DD_D, kIntrinsicMinMaxDouble, kIntrinsicFlagMax),
- INTRINSIC(JavaLangStrictMath, Max, DD_D, kIntrinsicMinMaxDouble, kIntrinsicFlagMax),
-
- INTRINSIC(JavaLangMath, Cos, D_D, kIntrinsicCos, 0),
- INTRINSIC(JavaLangMath, Sin, D_D, kIntrinsicSin, 0),
- INTRINSIC(JavaLangMath, Acos, D_D, kIntrinsicAcos, 0),
- INTRINSIC(JavaLangMath, Asin, D_D, kIntrinsicAsin, 0),
- INTRINSIC(JavaLangMath, Atan, D_D, kIntrinsicAtan, 0),
- INTRINSIC(JavaLangMath, Atan2, DD_D, kIntrinsicAtan2, 0),
- INTRINSIC(JavaLangMath, Cbrt, D_D, kIntrinsicCbrt, 0),
- INTRINSIC(JavaLangMath, Cosh, D_D, kIntrinsicCosh, 0),
- INTRINSIC(JavaLangMath, Exp, D_D, kIntrinsicExp, 0),
- INTRINSIC(JavaLangMath, Expm1, D_D, kIntrinsicExpm1, 0),
- INTRINSIC(JavaLangMath, Hypot, DD_D, kIntrinsicHypot, 0),
- INTRINSIC(JavaLangMath, Log, D_D, kIntrinsicLog, 0),
- INTRINSIC(JavaLangMath, Log10, D_D, kIntrinsicLog10, 0),
- INTRINSIC(JavaLangMath, NextAfter, DD_D, kIntrinsicNextAfter, 0),
- INTRINSIC(JavaLangMath, Sinh, D_D, kIntrinsicSinh, 0),
- INTRINSIC(JavaLangMath, Tan, D_D, kIntrinsicTan, 0),
- INTRINSIC(JavaLangMath, Tanh, D_D, kIntrinsicTanh, 0),
- INTRINSIC(JavaLangMath, Sqrt, D_D, kIntrinsicSqrt, 0),
- INTRINSIC(JavaLangStrictMath, Sqrt, D_D, kIntrinsicSqrt, 0),
-
- INTRINSIC(JavaLangMath, Ceil, D_D, kIntrinsicCeil, 0),
- INTRINSIC(JavaLangStrictMath, Ceil, D_D, kIntrinsicCeil, 0),
- INTRINSIC(JavaLangMath, Floor, D_D, kIntrinsicFloor, 0),
- INTRINSIC(JavaLangStrictMath, Floor, D_D, kIntrinsicFloor, 0),
- INTRINSIC(JavaLangMath, Rint, D_D, kIntrinsicRint, 0),
- INTRINSIC(JavaLangStrictMath, Rint, D_D, kIntrinsicRint, 0),
- INTRINSIC(JavaLangMath, Round, F_I, kIntrinsicRoundFloat, 0),
- INTRINSIC(JavaLangStrictMath, Round, F_I, kIntrinsicRoundFloat, 0),
- INTRINSIC(JavaLangMath, Round, D_J, kIntrinsicRoundDouble, 0),
- INTRINSIC(JavaLangStrictMath, Round, D_J, kIntrinsicRoundDouble, 0),
-
- INTRINSIC(JavaLangRefReference, ReferenceGetReferent, _Object, kIntrinsicReferenceGetReferent, 0),
-
- INTRINSIC(JavaLangString, CharAt, I_C, kIntrinsicCharAt, 0),
- INTRINSIC(JavaLangString, CompareTo, String_I, kIntrinsicCompareTo, 0),
- INTRINSIC(JavaLangString, Equals, Object_Z, kIntrinsicEquals, 0),
- INTRINSIC(JavaLangString, GetCharsNoCheck, IICharArrayI_V, kIntrinsicGetCharsNoCheck, 0),
- INTRINSIC(JavaLangString, IsEmpty, _Z, kIntrinsicIsEmptyOrLength, kIntrinsicFlagIsEmpty),
- INTRINSIC(JavaLangString, IndexOf, II_I, kIntrinsicIndexOf, kIntrinsicFlagNone),
- INTRINSIC(JavaLangString, IndexOf, I_I, kIntrinsicIndexOf, kIntrinsicFlagBase0),
- INTRINSIC(JavaLangString, Length, _I, kIntrinsicIsEmptyOrLength, kIntrinsicFlagLength),
-
- INTRINSIC(JavaLangStringFactory, NewStringFromBytes, ByteArrayIII_String,
- kIntrinsicNewStringFromBytes, kIntrinsicFlagNone),
- INTRINSIC(JavaLangStringFactory, NewStringFromChars, IICharArray_String,
- kIntrinsicNewStringFromChars, kIntrinsicFlagNone),
- INTRINSIC(JavaLangStringFactory, NewStringFromString, String_String,
- kIntrinsicNewStringFromString, kIntrinsicFlagNone),
-
- INTRINSIC(JavaLangThread, CurrentThread, _Thread, kIntrinsicCurrentThread, 0),
-
- INTRINSIC(LibcoreIoMemory, PeekByte, J_B, kIntrinsicPeek, kSignedByte),
- INTRINSIC(LibcoreIoMemory, PeekIntNative, J_I, kIntrinsicPeek, k32),
- INTRINSIC(LibcoreIoMemory, PeekLongNative, J_J, kIntrinsicPeek, k64),
- INTRINSIC(LibcoreIoMemory, PeekShortNative, J_S, kIntrinsicPeek, kSignedHalf),
- INTRINSIC(LibcoreIoMemory, PokeByte, JB_V, kIntrinsicPoke, kSignedByte),
- INTRINSIC(LibcoreIoMemory, PokeIntNative, JI_V, kIntrinsicPoke, k32),
- INTRINSIC(LibcoreIoMemory, PokeLongNative, JJ_V, kIntrinsicPoke, k64),
- INTRINSIC(LibcoreIoMemory, PokeShortNative, JS_V, kIntrinsicPoke, kSignedHalf),
-
- INTRINSIC(SunMiscUnsafe, CompareAndSwapInt, ObjectJII_Z, kIntrinsicCas,
- kIntrinsicFlagNone),
- INTRINSIC(SunMiscUnsafe, CompareAndSwapLong, ObjectJJJ_Z, kIntrinsicCas,
- kIntrinsicFlagIsLong),
- INTRINSIC(SunMiscUnsafe, CompareAndSwapObject, ObjectJObjectObject_Z, kIntrinsicCas,
- kIntrinsicFlagIsObject),
-
-#define UNSAFE_GET_PUT(type, code, type_flags) \
- INTRINSIC(SunMiscUnsafe, Get ## type, ObjectJ_ ## code, kIntrinsicUnsafeGet, \
- type_flags), \
- INTRINSIC(SunMiscUnsafe, Get ## type ## Volatile, ObjectJ_ ## code, kIntrinsicUnsafeGet, \
- (type_flags) | kIntrinsicFlagIsVolatile), \
- INTRINSIC(SunMiscUnsafe, Put ## type, ObjectJ ## code ## _V, kIntrinsicUnsafePut, \
- type_flags), \
- INTRINSIC(SunMiscUnsafe, Put ## type ## Volatile, ObjectJ ## code ## _V, kIntrinsicUnsafePut, \
- (type_flags) | kIntrinsicFlagIsVolatile), \
- INTRINSIC(SunMiscUnsafe, PutOrdered ## type, ObjectJ ## code ## _V, kIntrinsicUnsafePut, \
- (type_flags) | kIntrinsicFlagIsOrdered)
-
- UNSAFE_GET_PUT(Int, I, kIntrinsicFlagNone),
- UNSAFE_GET_PUT(Long, J, kIntrinsicFlagIsLong),
- UNSAFE_GET_PUT(Object, Object, kIntrinsicFlagIsObject),
-#undef UNSAFE_GET_PUT
-
- // 1.8
- INTRINSIC(SunMiscUnsafe, GetAndAddInt, ObjectJI_I, kIntrinsicUnsafeGetAndAddInt, 0),
- INTRINSIC(SunMiscUnsafe, GetAndAddLong, ObjectJJ_J, kIntrinsicUnsafeGetAndAddLong, 0),
- INTRINSIC(SunMiscUnsafe, GetAndSetInt, ObjectJI_I, kIntrinsicUnsafeGetAndSetInt, 0),
- INTRINSIC(SunMiscUnsafe, GetAndSetLong, ObjectJJ_J, kIntrinsicUnsafeGetAndSetLong, 0),
- INTRINSIC(SunMiscUnsafe, GetAndSetObject, ObjectJObject_Object, kIntrinsicUnsafeGetAndSetObject, 0),
- INTRINSIC(SunMiscUnsafe, LoadFence, _V, kIntrinsicUnsafeLoadFence, 0),
- INTRINSIC(SunMiscUnsafe, StoreFence, _V, kIntrinsicUnsafeStoreFence, 0),
- INTRINSIC(SunMiscUnsafe, FullFence, _V, kIntrinsicUnsafeFullFence, 0),
-
- INTRINSIC(JavaLangSystem, ArrayCopy, CharArrayICharArrayII_V , kIntrinsicSystemArrayCopyCharArray,
- 0),
- INTRINSIC(JavaLangSystem, ArrayCopy, ObjectIObjectII_V , kIntrinsicSystemArrayCopy,
- 0),
-
- INTRINSIC(JavaLangInteger, RotateRight, II_I, kIntrinsicRotateRight, k32),
- INTRINSIC(JavaLangLong, RotateRight, JI_J, kIntrinsicRotateRight, k64),
- INTRINSIC(JavaLangInteger, RotateLeft, II_I, kIntrinsicRotateLeft, k32),
- INTRINSIC(JavaLangLong, RotateLeft, JI_J, kIntrinsicRotateLeft, k64),
-
-#undef INTRINSIC
-};
-
-DexFileMethodInliner::DexFileMethodInliner()
- : lock_("DexFileMethodInliner lock", kDexFileMethodInlinerLock),
- dex_file_(nullptr) {
- static_assert(kClassCacheFirst == 0, "kClassCacheFirst not 0");
- static_assert(arraysize(kClassCacheNames) == kClassCacheLast,
- "bad arraysize for kClassCacheNames");
- static_assert(kNameCacheFirst == 0, "kNameCacheFirst not 0");
- static_assert(arraysize(kNameCacheNames) == kNameCacheLast,
- "bad arraysize for kNameCacheNames");
- static_assert(kProtoCacheFirst == 0, "kProtoCacheFirst not 0");
- static_assert(arraysize(kProtoCacheDefs) == kProtoCacheLast,
- "bad arraysize kProtoCacheNames");
-}
-
-DexFileMethodInliner::~DexFileMethodInliner() {
-}
-
-bool DexFileMethodInliner::AnalyseMethodCode(verifier::MethodVerifier* verifier) {
- InlineMethod method;
- bool success = InlineMethodAnalyser::AnalyseMethodCode(verifier, &method);
- return success && AddInlineMethod(verifier->GetMethodReference().dex_method_index, method);
-}
-
-InlineMethodFlags DexFileMethodInliner::IsIntrinsicOrSpecial(uint32_t method_index) {
- ReaderMutexLock mu(Thread::Current(), lock_);
- auto it = inline_methods_.find(method_index);
- if (it != inline_methods_.end()) {
- DCHECK_NE(it->second.flags & (kInlineIntrinsic | kInlineSpecial), 0);
- return it->second.flags;
- } else {
- return kNoInlineMethodFlags;
- }
-}
-
-bool DexFileMethodInliner::IsIntrinsic(uint32_t method_index, InlineMethod* intrinsic) {
- ReaderMutexLock mu(Thread::Current(), lock_);
- auto it = inline_methods_.find(method_index);
- bool res = (it != inline_methods_.end() && (it->second.flags & kInlineIntrinsic) != 0);
- if (res && intrinsic != nullptr) {
- *intrinsic = it->second;
- }
- return res;
-}
-
-bool DexFileMethodInliner::IsSpecial(uint32_t method_index) {
- ReaderMutexLock mu(Thread::Current(), lock_);
- auto it = inline_methods_.find(method_index);
- return it != inline_methods_.end() && (it->second.flags & kInlineSpecial) != 0;
-}
-
-uint32_t DexFileMethodInliner::FindClassIndex(const DexFile* dex_file, IndexCache* cache,
- ClassCacheIndex index) {
- uint32_t* class_index = &cache->class_indexes[index];
- if (*class_index != kIndexUnresolved) {
- return *class_index;
- }
-
- const DexFile::TypeId* type_id = dex_file->FindTypeId(kClassCacheNames[index]);
- if (type_id == nullptr) {
- *class_index = kIndexNotFound;
- return *class_index;
- }
- *class_index = dex_file->GetIndexForTypeId(*type_id);
- return *class_index;
-}
-
-uint32_t DexFileMethodInliner::FindNameIndex(const DexFile* dex_file, IndexCache* cache,
- NameCacheIndex index) {
- uint32_t* name_index = &cache->name_indexes[index];
- if (*name_index != kIndexUnresolved) {
- return *name_index;
- }
-
- const DexFile::StringId* string_id = dex_file->FindStringId(kNameCacheNames[index]);
- if (string_id == nullptr) {
- *name_index = kIndexNotFound;
- return *name_index;
- }
- *name_index = dex_file->GetIndexForStringId(*string_id);
- return *name_index;
-}
-
-uint32_t DexFileMethodInliner::FindProtoIndex(const DexFile* dex_file, IndexCache* cache,
- ProtoCacheIndex index) {
- uint32_t* proto_index = &cache->proto_indexes[index];
- if (*proto_index != kIndexUnresolved) {
- return *proto_index;
- }
-
- const ProtoDef& proto_def = kProtoCacheDefs[index];
- uint32_t return_index = FindClassIndex(dex_file, cache, proto_def.return_type);
- if (return_index == kIndexNotFound) {
- *proto_index = kIndexNotFound;
- return *proto_index;
- }
- uint16_t return_type = static_cast<uint16_t>(return_index);
- DCHECK_EQ(static_cast<uint32_t>(return_type), return_index);
-
- uint32_t signature_length = proto_def.param_count;
- uint16_t signature_type_idxs[kProtoMaxParams];
- for (uint32_t i = 0; i != signature_length; ++i) {
- uint32_t param_index = FindClassIndex(dex_file, cache, proto_def.params[i]);
- if (param_index == kIndexNotFound) {
- *proto_index = kIndexNotFound;
- return *proto_index;
- }
- signature_type_idxs[i] = static_cast<uint16_t>(param_index);
- DCHECK_EQ(static_cast<uint32_t>(signature_type_idxs[i]), param_index);
- }
-
- const DexFile::ProtoId* proto_id = dex_file->FindProtoId(return_type, signature_type_idxs,
- signature_length);
- if (proto_id == nullptr) {
- *proto_index = kIndexNotFound;
- return *proto_index;
- }
- *proto_index = dex_file->GetIndexForProtoId(*proto_id);
- return *proto_index;
-}
-
-uint32_t DexFileMethodInliner::FindMethodIndex(const DexFile* dex_file, IndexCache* cache,
- const MethodDef& method_def) {
- uint32_t declaring_class_index = FindClassIndex(dex_file, cache, method_def.declaring_class);
- if (declaring_class_index == kIndexNotFound) {
- return kIndexNotFound;
- }
- uint32_t name_index = FindNameIndex(dex_file, cache, method_def.name);
- if (name_index == kIndexNotFound) {
- return kIndexNotFound;
- }
- uint32_t proto_index = FindProtoIndex(dex_file, cache, method_def.proto);
- if (proto_index == kIndexNotFound) {
- return kIndexNotFound;
- }
- const DexFile::MethodId* method_id =
- dex_file->FindMethodId(dex_file->GetTypeId(declaring_class_index),
- dex_file->GetStringId(name_index),
- dex_file->GetProtoId(proto_index));
- if (method_id == nullptr) {
- return kIndexNotFound;
- }
- return dex_file->GetIndexForMethodId(*method_id);
-}
-
-DexFileMethodInliner::IndexCache::IndexCache() {
- std::fill_n(class_indexes, arraysize(class_indexes), kIndexUnresolved);
- std::fill_n(name_indexes, arraysize(name_indexes), kIndexUnresolved);
- std::fill_n(proto_indexes, arraysize(proto_indexes), kIndexUnresolved);
-}
-
-void DexFileMethodInliner::FindIntrinsics(const DexFile* dex_file) {
- DCHECK(dex_file != nullptr);
- DCHECK(dex_file_ == nullptr);
- IndexCache cache;
- for (const IntrinsicDef& def : kIntrinsicMethods) {
- uint32_t method_idx = FindMethodIndex(dex_file, &cache, def.method_def);
- if (method_idx != kIndexNotFound) {
- DCHECK(inline_methods_.find(method_idx) == inline_methods_.end());
- inline_methods_.Put(method_idx, def.intrinsic);
- }
- }
- dex_file_ = dex_file;
-}
-
-bool DexFileMethodInliner::AddInlineMethod(int32_t method_idx, const InlineMethod& method) {
- WriterMutexLock mu(Thread::Current(), lock_);
- if (LIKELY(inline_methods_.find(method_idx) == inline_methods_.end())) {
- inline_methods_.Put(method_idx, method);
- return true;
- } else {
- if (PrettyMethod(method_idx, *dex_file_) == "int java.lang.String.length()") {
- // TODO: String.length is both kIntrinsicIsEmptyOrLength and kInlineOpIGet.
- } else {
- LOG(WARNING) << "Inliner: " << PrettyMethod(method_idx, *dex_file_) << " already inline";
- }
- return false;
- }
-}
-
-} // namespace art
diff --git a/compiler/dex/quick/dex_file_method_inliner.h b/compiler/dex/quick/dex_file_method_inliner.h
deleted file mode 100644
index f4ae5a5..0000000
--- a/compiler/dex/quick/dex_file_method_inliner.h
+++ /dev/null
@@ -1,395 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ART_COMPILER_DEX_QUICK_DEX_FILE_METHOD_INLINER_H_
-#define ART_COMPILER_DEX_QUICK_DEX_FILE_METHOD_INLINER_H_
-
-#include <stdint.h>
-
-#include "base/enums.h"
-#include "base/mutex.h"
-#include "base/macros.h"
-#include "safe_map.h"
-#include "dex_file.h"
-#include "quick/inline_method_analyser.h"
-
-namespace art {
-
-namespace verifier {
-class MethodVerifier;
-} // namespace verifier
-
-enum OpSize {
- k32,
- k64,
- kSignedHalf,
- kSignedByte,
-};
-
-/**
- * Handles inlining of methods from a particular DexFile.
- *
- * Intrinsics are a special case of inline methods. The DexFile indices for
- * all the supported intrinsic methods are looked up once by the FindIntrinsics
- * function and cached by this class for quick lookup by the method index.
- *
- * TODO: Detect short methods (at least getters, setters and empty functions)
- * from the verifier and mark them for inlining. Inline these methods early
- * during compilation to allow further optimizations. Similarly, provide
- * additional information about intrinsics to the early phases of compilation.
- */
-class DexFileMethodInliner {
- public:
- DexFileMethodInliner();
- ~DexFileMethodInliner();
-
- /**
- * Analyse method code to determine if the method is a candidate for inlining.
- * If it is, record its data for later.
- *
- * @param verifier the method verifier holding data about the method to analyse.
- * @return true if the method is a candidate for inlining, false otherwise.
- */
- bool AnalyseMethodCode(verifier::MethodVerifier* verifier)
- REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!lock_);
-
- /**
- * Check whether a particular method index corresponds to an intrinsic or special function.
- */
- InlineMethodFlags IsIntrinsicOrSpecial(uint32_t method_index) REQUIRES(!lock_);
-
- /**
- * Check whether a particular method index corresponds to an intrinsic function.
- */
- bool IsIntrinsic(uint32_t method_index, InlineMethod* intrinsic) REQUIRES(!lock_);
-
- /**
- * Check whether a particular method index corresponds to a special function.
- */
- bool IsSpecial(uint32_t method_index) REQUIRES(!lock_);
-
- /**
- * To avoid multiple lookups of a class by its descriptor, we cache its
- * type index in the IndexCache. These are the indexes into the IndexCache
- * class_indexes array.
- */
- enum ClassCacheIndex : uint8_t { // unit8_t to save space, make larger if needed
- kClassCacheFirst = 0,
- kClassCacheBoolean = kClassCacheFirst,
- kClassCacheByte,
- kClassCacheChar,
- kClassCacheShort,
- kClassCacheInt,
- kClassCacheLong,
- kClassCacheFloat,
- kClassCacheDouble,
- kClassCacheVoid,
- kClassCacheJavaLangByteArray,
- kClassCacheJavaLangCharArray,
- kClassCacheJavaLangIntArray,
- kClassCacheJavaLangObject,
- kClassCacheJavaLangRefReference,
- kClassCacheJavaLangString,
- kClassCacheJavaLangStringBuffer,
- kClassCacheJavaLangStringBuilder,
- kClassCacheJavaLangStringFactory,
- kClassCacheJavaLangDouble,
- kClassCacheJavaLangFloat,
- kClassCacheJavaLangInteger,
- kClassCacheJavaLangLong,
- kClassCacheJavaLangShort,
- kClassCacheJavaLangMath,
- kClassCacheJavaLangStrictMath,
- kClassCacheJavaLangThread,
- kClassCacheJavaNioCharsetCharset,
- kClassCacheLibcoreIoMemory,
- kClassCacheSunMiscUnsafe,
- kClassCacheJavaLangSystem,
- kClassCacheLast
- };
-
- /**
- * To avoid multiple lookups of a method name string, we cache its string
- * index in the IndexCache. These are the indexes into the IndexCache
- * name_indexes array.
- */
- enum NameCacheIndex : uint8_t { // unit8_t to save space, make larger if needed
- kNameCacheFirst = 0,
- kNameCacheReverse = kNameCacheFirst,
- kNameCacheReverseBytes,
- kNameCacheDoubleToRawLongBits,
- kNameCacheLongBitsToDouble,
- kNameCacheFloatToRawIntBits,
- kNameCacheIntBitsToFloat,
- kNameCacheAbs,
- kNameCacheMax,
- kNameCacheMin,
- kNameCacheCos,
- kNameCacheSin,
- kNameCacheAcos,
- kNameCacheAsin,
- kNameCacheAtan,
- kNameCacheAtan2,
- kNameCacheCbrt,
- kNameCacheCosh,
- kNameCacheExp,
- kNameCacheExpm1,
- kNameCacheHypot,
- kNameCacheLog,
- kNameCacheLog10,
- kNameCacheNextAfter,
- kNameCacheSinh,
- kNameCacheTan,
- kNameCacheTanh,
- kNameCacheSqrt,
- kNameCacheCeil,
- kNameCacheFloor,
- kNameCacheRint,
- kNameCacheRound,
- kNameCacheReferenceGetReferent,
- kNameCacheCharAt,
- kNameCacheCompareTo,
- kNameCacheEquals,
- kNameCacheGetCharsNoCheck,
- kNameCacheIsEmpty,
- kNameCacheFloatToIntBits,
- kNameCacheDoubleToLongBits,
- kNameCacheIsInfinite,
- kNameCacheIsNaN,
- kNameCacheIndexOf,
- kNameCacheLength,
- kNameCacheInit,
- kNameCacheNewStringFromBytes,
- kNameCacheNewStringFromChars,
- kNameCacheNewStringFromString,
- kNameCacheCurrentThread,
- kNameCachePeekByte,
- kNameCachePeekIntNative,
- kNameCachePeekLongNative,
- kNameCachePeekShortNative,
- kNameCachePokeByte,
- kNameCachePokeIntNative,
- kNameCachePokeLongNative,
- kNameCachePokeShortNative,
- kNameCacheCompareAndSwapInt,
- kNameCacheCompareAndSwapLong,
- kNameCacheCompareAndSwapObject,
- kNameCacheGetInt,
- kNameCacheGetIntVolatile,
- kNameCachePutInt,
- kNameCachePutIntVolatile,
- kNameCachePutOrderedInt,
- kNameCacheGetLong,
- kNameCacheGetLongVolatile,
- kNameCachePutLong,
- kNameCachePutLongVolatile,
- kNameCachePutOrderedLong,
- kNameCacheGetObject,
- kNameCacheGetObjectVolatile,
- kNameCachePutObject,
- kNameCachePutObjectVolatile,
- kNameCachePutOrderedObject,
- kNameCacheGetAndAddInt,
- kNameCacheGetAndAddLong,
- kNameCacheGetAndSetInt,
- kNameCacheGetAndSetLong,
- kNameCacheGetAndSetObject,
- kNameCacheLoadFence,
- kNameCacheStoreFence,
- kNameCacheFullFence,
- kNameCacheArrayCopy,
- kNameCacheBitCount,
- kNameCacheCompare,
- kNameCacheHighestOneBit,
- kNameCacheLowestOneBit,
- kNameCacheNumberOfLeadingZeros,
- kNameCacheNumberOfTrailingZeros,
- kNameCacheRotateRight,
- kNameCacheRotateLeft,
- kNameCacheSignum,
- kNameCacheLast
- };
-
- /**
- * To avoid multiple lookups of a method signature, we cache its proto
- * index in the IndexCache. These are the indexes into the IndexCache
- * proto_indexes array.
- */
- enum ProtoCacheIndex : uint8_t { // unit8_t to save space, make larger if needed
- kProtoCacheFirst = 0,
- kProtoCacheI_I = kProtoCacheFirst,
- kProtoCacheJ_J,
- kProtoCacheS_S,
- kProtoCacheD_D,
- kProtoCacheDD_D,
- kProtoCacheF_F,
- kProtoCacheFF_F,
- kProtoCacheD_J,
- kProtoCacheD_Z,
- kProtoCacheJ_D,
- kProtoCacheF_I,
- kProtoCacheF_Z,
- kProtoCacheI_F,
- kProtoCacheII_I,
- kProtoCacheI_C,
- kProtoCacheString_I,
- kProtoCache_Z,
- kProtoCache_I,
- kProtoCache_Object,
- kProtoCache_Thread,
- kProtoCacheJ_B,
- kProtoCacheJ_I,
- kProtoCacheJ_S,
- kProtoCacheJB_V,
- kProtoCacheJI_V,
- kProtoCacheJJ_J,
- kProtoCacheJJ_I,
- kProtoCacheJJ_V,
- kProtoCacheJS_V,
- kProtoCacheObject_Z,
- kProtoCacheJI_J,
- kProtoCacheObjectJII_Z,
- kProtoCacheObjectJJJ_Z,
- kProtoCacheObjectJObjectObject_Z,
- kProtoCacheObjectJ_I,
- kProtoCacheObjectJI_I,
- kProtoCacheObjectJI_V,
- kProtoCacheObjectJ_J,
- kProtoCacheObjectJJ_J,
- kProtoCacheObjectJJ_V,
- kProtoCacheObjectJ_Object,
- kProtoCacheObjectJObject_V,
- kProtoCacheObjectJObject_Object,
- kProtoCacheCharArrayICharArrayII_V,
- kProtoCacheObjectIObjectII_V,
- kProtoCacheIICharArrayI_V,
- kProtoCacheByteArrayIII_String,
- kProtoCacheIICharArray_String,
- kProtoCacheString_String,
- kProtoCache_V,
- kProtoCacheByteArray_V,
- kProtoCacheByteArrayI_V,
- kProtoCacheByteArrayII_V,
- kProtoCacheByteArrayIII_V,
- kProtoCacheByteArrayIIString_V,
- kProtoCacheByteArrayString_V,
- kProtoCacheByteArrayIICharset_V,
- kProtoCacheByteArrayCharset_V,
- kProtoCacheCharArray_V,
- kProtoCacheCharArrayII_V,
- kProtoCacheIICharArray_V,
- kProtoCacheIntArrayII_V,
- kProtoCacheString_V,
- kProtoCacheStringBuffer_V,
- kProtoCacheStringBuilder_V,
- kProtoCacheLast
- };
-
- private:
- /**
- * The maximum number of method parameters we support in the ProtoDef.
- */
- static constexpr uint32_t kProtoMaxParams = 6;
-
- /**
- * The method signature (proto) definition using cached class indexes.
- * The return_type and params are used with the IndexCache to look up
- * appropriate class indexes to be passed to DexFile::FindProtoId().
- */
- struct ProtoDef {
- ClassCacheIndex return_type;
- uint8_t param_count;
- ClassCacheIndex params[kProtoMaxParams];
- };
-
- /**
- * The method definition using cached class, name and proto indexes.
- * The class index, method name index and proto index are used with
- * IndexCache to look up appropriate parameters for DexFile::FindMethodId().
- */
- struct MethodDef {
- ClassCacheIndex declaring_class;
- NameCacheIndex name;
- ProtoCacheIndex proto;
- };
-
- /**
- * The definition of an intrinsic function binds the method definition
- * to an Intrinsic.
- */
- struct IntrinsicDef {
- MethodDef method_def;
- InlineMethod intrinsic;
- };
-
- /**
- * Cache for class, method name and method signature indexes used during
- * intrinsic function lookup to avoid multiple lookups of the same items.
- *
- * Many classes have multiple intrinsics and/or they are used in multiple
- * method signatures and we want to avoid repeated lookups since they are
- * not exactly cheap. The method names and method signatures are sometimes
- * reused and therefore cached as well.
- */
- struct IndexCache {
- IndexCache();
-
- uint32_t class_indexes[kClassCacheLast - kClassCacheFirst];
- uint32_t name_indexes[kNameCacheLast - kNameCacheFirst];
- uint32_t proto_indexes[kProtoCacheLast - kProtoCacheFirst];
- };
-
- static const char* const kClassCacheNames[];
- static const char* const kNameCacheNames[];
- static const ProtoDef kProtoCacheDefs[];
- static const IntrinsicDef kIntrinsicMethods[];
-
- static const uint32_t kIndexNotFound = static_cast<uint32_t>(-1);
- static const uint32_t kIndexUnresolved = static_cast<uint32_t>(-2);
-
- static uint32_t FindClassIndex(const DexFile* dex_file, IndexCache* cache,
- ClassCacheIndex index);
- static uint32_t FindNameIndex(const DexFile* dex_file, IndexCache* cache,
- NameCacheIndex index);
- static uint32_t FindProtoIndex(const DexFile* dex_file, IndexCache* cache,
- ProtoCacheIndex index);
- static uint32_t FindMethodIndex(const DexFile* dex_file, IndexCache* cache,
- const MethodDef& method_def);
-
- /**
- * Find all known intrinsic methods in the dex_file and cache their indices.
- *
- * Only DexFileToMethodInlinerMap may call this function to initialize the inliner.
- */
- void FindIntrinsics(const DexFile* dex_file) REQUIRES(lock_);
-
- friend class DexFileToMethodInlinerMap;
-
- bool AddInlineMethod(int32_t method_idx, const InlineMethod& method) REQUIRES(!lock_);
-
- ReaderWriterMutex lock_;
- /*
- * Maps method indexes (for the particular DexFile) to Intrinsic defintions.
- */
- SafeMap<uint32_t, InlineMethod> inline_methods_ GUARDED_BY(lock_);
- const DexFile* dex_file_;
-
- DISALLOW_COPY_AND_ASSIGN(DexFileMethodInliner);
-};
-
-} // namespace art
-
-#endif // ART_COMPILER_DEX_QUICK_DEX_FILE_METHOD_INLINER_H_
diff --git a/compiler/dex/quick/dex_file_to_method_inliner_map.cc b/compiler/dex/quick/dex_file_to_method_inliner_map.cc
deleted file mode 100644
index 2fec183..0000000
--- a/compiler/dex/quick/dex_file_to_method_inliner_map.cc
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <algorithm>
-#include <utility>
-#include "thread.h"
-#include "thread-inl.h"
-#include "base/mutex.h"
-#include "base/mutex-inl.h"
-#include "base/logging.h"
-#include "driver/compiler_driver.h"
-
-#include "dex_file_to_method_inliner_map.h"
-
-namespace art {
-
-DexFileToMethodInlinerMap::DexFileToMethodInlinerMap()
- : lock_("DexFileToMethodInlinerMap lock", kDexFileToMethodInlinerMapLock) {
-}
-
-DexFileToMethodInlinerMap::~DexFileToMethodInlinerMap() {
- for (auto& entry : inliners_) {
- delete entry.second;
- }
-}
-
-DexFileMethodInliner* DexFileToMethodInlinerMap::GetMethodInliner(const DexFile* dex_file) {
- Thread* self = Thread::Current();
- {
- ReaderMutexLock mu(self, lock_);
- auto it = inliners_.find(dex_file);
- if (it != inliners_.end()) {
- return it->second;
- }
- }
-
- // We need to acquire our lock_ to modify inliners_ but we want to release it
- // before we initialize the new inliner. However, we need to acquire the
- // new inliner's lock_ before we release our lock_ to prevent another thread
- // from using the uninitialized inliner. This requires explicit calls to
- // ExclusiveLock()/ExclusiveUnlock() on one of the locks, the other one
- // can use WriterMutexLock.
- DexFileMethodInliner* locked_inliner;
- {
- WriterMutexLock mu(self, lock_);
- DexFileMethodInliner** inliner = &inliners_[dex_file]; // inserts new entry if not found
- if (*inliner) {
- return *inliner;
- }
- *inliner = new DexFileMethodInliner;
- DCHECK(*inliner != nullptr);
- locked_inliner = *inliner;
- locked_inliner->lock_.ExclusiveLock(self); // Acquire inliner's lock_ before releasing lock_.
- }
- locked_inliner->FindIntrinsics(dex_file);
- locked_inliner->lock_.ExclusiveUnlock(self);
- return locked_inliner;
-}
-
-} // namespace art
diff --git a/compiler/dex/quick/dex_file_to_method_inliner_map.h b/compiler/dex/quick/dex_file_to_method_inliner_map.h
deleted file mode 100644
index 215dc12..0000000
--- a/compiler/dex/quick/dex_file_to_method_inliner_map.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ART_COMPILER_DEX_QUICK_DEX_FILE_TO_METHOD_INLINER_MAP_H_
-#define ART_COMPILER_DEX_QUICK_DEX_FILE_TO_METHOD_INLINER_MAP_H_
-
-#include <map>
-#include <vector>
-#include "base/macros.h"
-#include "base/mutex.h"
-
-#include "dex/quick/dex_file_method_inliner.h"
-
-namespace art {
-
-class CompilerDriver;
-class DexFile;
-
-/**
- * Map each DexFile to its DexFileMethodInliner.
- *
- * The method inliner is created and initialized the first time it's requested
- * for a particular DexFile.
- */
-class DexFileToMethodInlinerMap {
- public:
- DexFileToMethodInlinerMap();
- ~DexFileToMethodInlinerMap();
-
- DexFileMethodInliner* GetMethodInliner(const DexFile* dex_file) NO_THREAD_SAFETY_ANALYSIS;
- // TODO: There is an irregular non-scoped use of locks that defeats annotalysis with -O0.
- // Fix the NO_THREAD_SAFETY_ANALYSIS when this works and add the appropriate LOCKS_EXCLUDED.
-
- private:
- ReaderWriterMutex lock_;
- std::map<const DexFile*, DexFileMethodInliner*> inliners_ GUARDED_BY(lock_);
-
- DISALLOW_COPY_AND_ASSIGN(DexFileToMethodInlinerMap);
-};
-
-} // namespace art
-
-#endif // ART_COMPILER_DEX_QUICK_DEX_FILE_TO_METHOD_INLINER_MAP_H_
diff --git a/compiler/dex/quick_compiler_callbacks.cc b/compiler/dex/quick_compiler_callbacks.cc
index 2532bda..932eb51 100644
--- a/compiler/dex/quick_compiler_callbacks.cc
+++ b/compiler/dex/quick_compiler_callbacks.cc
@@ -16,7 +16,6 @@
#include "quick_compiler_callbacks.h"
-#include "quick/dex_file_to_method_inliner_map.h"
#include "verifier/method_verifier-inl.h"
#include "verification_results.h"
@@ -24,8 +23,6 @@
void QuickCompilerCallbacks::MethodVerified(verifier::MethodVerifier* verifier) {
verification_results_->ProcessVerifiedMethod(verifier);
- MethodReference ref = verifier->GetMethodReference();
- method_inliner_map_->GetMethodInliner(ref.dex_file)->AnalyseMethodCode(verifier);
}
void QuickCompilerCallbacks::ClassRejected(ClassReference ref) {
diff --git a/compiler/dex/quick_compiler_callbacks.h b/compiler/dex/quick_compiler_callbacks.h
index 824194c..34fd88b 100644
--- a/compiler/dex/quick_compiler_callbacks.h
+++ b/compiler/dex/quick_compiler_callbacks.h
@@ -22,19 +22,15 @@
namespace art {
class VerificationResults;
-class DexFileToMethodInlinerMap;
class QuickCompilerCallbacks FINAL : public CompilerCallbacks {
public:
QuickCompilerCallbacks(VerificationResults* verification_results,
- DexFileToMethodInlinerMap* method_inliner_map,
CompilerCallbacks::CallbackMode mode)
: CompilerCallbacks(mode),
verification_results_(verification_results),
- method_inliner_map_(method_inliner_map),
verifier_deps_(nullptr) {
CHECK(verification_results != nullptr);
- CHECK(method_inliner_map != nullptr);
}
~QuickCompilerCallbacks() { }
@@ -59,7 +55,6 @@
private:
VerificationResults* const verification_results_;
- DexFileToMethodInlinerMap* const method_inliner_map_;
verifier::VerifierDeps* verifier_deps_;
};
diff --git a/compiler/driver/compiled_method_storage_test.cc b/compiler/driver/compiled_method_storage_test.cc
index 6863f42..5063d71 100644
--- a/compiler/driver/compiled_method_storage_test.cc
+++ b/compiler/driver/compiled_method_storage_test.cc
@@ -21,17 +21,14 @@
#include "compiler_driver.h"
#include "compiler_options.h"
#include "dex/verification_results.h"
-#include "dex/quick/dex_file_to_method_inliner_map.h"
namespace art {
TEST(CompiledMethodStorage, Deduplicate) {
CompilerOptions compiler_options;
VerificationResults verification_results(&compiler_options);
- DexFileToMethodInlinerMap method_inliner_map;
CompilerDriver driver(&compiler_options,
&verification_results,
- &method_inliner_map,
Compiler::kOptimizing,
/* instruction_set_ */ kNone,
/* instruction_set_features */ nullptr,
diff --git a/compiler/driver/compiler_driver-inl.h b/compiler/driver/compiler_driver-inl.h
index 4b913f4..2d0dd3c 100644
--- a/compiler/driver/compiler_driver-inl.h
+++ b/compiler/driver/compiler_driver-inl.h
@@ -26,7 +26,7 @@
#include "dex_compilation_unit.h"
#include "mirror/class_loader.h"
#include "mirror/dex_cache-inl.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
#include "handle_scope-inl.h"
namespace art {
@@ -37,7 +37,7 @@
inline mirror::ClassLoader* CompilerDriver::GetClassLoader(const ScopedObjectAccess& soa,
const DexCompilationUnit* mUnit) {
- return soa.Decode<mirror::ClassLoader*>(mUnit->GetClassLoader());
+ return soa.Decode<mirror::ClassLoader>(mUnit->GetClassLoader()).Decode();
}
inline mirror::Class* CompilerDriver::ResolveClass(
@@ -45,7 +45,7 @@
Handle<mirror::ClassLoader> class_loader, uint16_t cls_index,
const DexCompilationUnit* mUnit) {
DCHECK_EQ(dex_cache->GetDexFile(), mUnit->GetDexFile());
- DCHECK_EQ(class_loader.Get(), soa.Decode<mirror::ClassLoader*>(mUnit->GetClassLoader()));
+ DCHECK_EQ(class_loader.Get(), GetClassLoader(soa, mUnit));
mirror::Class* cls = mUnit->GetClassLinker()->ResolveType(
*mUnit->GetDexFile(), cls_index, dex_cache, class_loader);
DCHECK_EQ(cls == nullptr, soa.Self()->IsExceptionPending());
@@ -60,7 +60,7 @@
const ScopedObjectAccess& soa, Handle<mirror::DexCache> dex_cache,
Handle<mirror::ClassLoader> class_loader, const DexCompilationUnit* mUnit) {
DCHECK_EQ(dex_cache->GetDexFile(), mUnit->GetDexFile());
- DCHECK_EQ(class_loader.Get(), soa.Decode<mirror::ClassLoader*>(mUnit->GetClassLoader()));
+ DCHECK_EQ(class_loader.Get(), GetClassLoader(soa, mUnit));
const DexFile::MethodId& referrer_method_id =
mUnit->GetDexFile()->GetMethodId(mUnit->GetDexMethodIndex());
return ResolveClass(soa, dex_cache, class_loader, referrer_method_id.class_idx_, mUnit);
@@ -95,7 +95,7 @@
const ScopedObjectAccess& soa, Handle<mirror::DexCache> dex_cache,
Handle<mirror::ClassLoader> class_loader, const DexCompilationUnit* mUnit,
uint32_t field_idx, bool is_static) {
- DCHECK_EQ(class_loader.Get(), soa.Decode<mirror::ClassLoader*>(mUnit->GetClassLoader()));
+ DCHECK_EQ(class_loader.Get(), GetClassLoader(soa, mUnit));
return ResolveFieldWithDexFile(soa, dex_cache, class_loader, mUnit->GetDexFile(), field_idx,
is_static);
}
@@ -258,7 +258,7 @@
ScopedObjectAccess& soa, Handle<mirror::DexCache> dex_cache,
Handle<mirror::ClassLoader> class_loader, const DexCompilationUnit* mUnit,
uint32_t method_idx, InvokeType invoke_type, bool check_incompatible_class_change) {
- DCHECK_EQ(class_loader.Get(), soa.Decode<mirror::ClassLoader*>(mUnit->GetClassLoader()));
+ DCHECK_EQ(class_loader.Get(), GetClassLoader(soa, mUnit));
ArtMethod* resolved_method =
check_incompatible_class_change
? mUnit->GetClassLinker()->ResolveMethod<ClassLinker::kForceICCECheck>(
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index f1d3116..2ec3f16 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -44,9 +44,8 @@
#include "dex/dex_to_dex_compiler.h"
#include "dex/verification_results.h"
#include "dex/verified_method.h"
-#include "dex/quick/dex_file_method_inliner.h"
-#include "dex/quick/dex_file_to_method_inliner_map.h"
#include "driver/compiler_options.h"
+#include "intrinsics_enum.h"
#include "jni_internal.h"
#include "object_lock.h"
#include "runtime.h"
@@ -60,7 +59,7 @@
#include "mirror/object-inl.h"
#include "mirror/object_array-inl.h"
#include "mirror/throwable.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
#include "ScopedLocalRef.h"
#include "handle_scope-inl.h"
#include "thread.h"
@@ -353,7 +352,6 @@
CompilerDriver::CompilerDriver(
const CompilerOptions* compiler_options,
VerificationResults* verification_results,
- DexFileToMethodInlinerMap* method_inliner_map,
Compiler::Kind compiler_kind,
InstructionSet instruction_set,
const InstructionSetFeatures* instruction_set_features,
@@ -370,7 +368,6 @@
const ProfileCompilationInfo* profile_compilation_info)
: compiler_options_(compiler_options),
verification_results_(verification_results),
- method_inliner_map_(method_inliner_map),
compiler_(Compiler::Create(this, compiler_kind)),
compiler_kind_(compiler_kind),
instruction_set_(instruction_set == kArm ? kThumb2: instruction_set),
@@ -401,7 +398,6 @@
dex_to_dex_references_(),
current_dex_to_dex_methods_(nullptr) {
DCHECK(compiler_options_ != nullptr);
- DCHECK(method_inliner_map_ != nullptr);
compiler_->Init();
@@ -463,6 +459,29 @@
}
#undef CREATE_TRAMPOLINE
+static void SetupIntrinsic(Thread* self,
+ Intrinsics intrinsic,
+ InvokeType invoke_type,
+ const char* class_name,
+ const char* method_name,
+ const char* signature)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+ PointerSize image_size = class_linker->GetImagePointerSize();
+ mirror::Class* cls = class_linker->FindSystemClass(self, class_name);
+ if (cls == nullptr) {
+ LOG(FATAL) << "Could not find class of intrinsic " << class_name;
+ }
+ ArtMethod* method = (invoke_type == kStatic || invoke_type == kDirect)
+ ? cls->FindDeclaredDirectMethod(method_name, signature, image_size)
+ : cls->FindDeclaredVirtualMethod(method_name, signature, image_size);
+ if (method == nullptr) {
+ LOG(FATAL) << "Could not find method of intrinsic " << class_name << method_name << signature;
+ }
+ DCHECK_EQ(method->GetInvokeType(), invoke_type);
+ method->SetIntrinsic(static_cast<uint32_t>(intrinsic));
+}
+
void CompilerDriver::CompileAll(jobject class_loader,
const std::vector<const DexFile*>& dex_files,
TimingLogger* timings) {
@@ -477,6 +496,17 @@
// 3) Attempt to verify all classes
// 4) Attempt to initialize image classes, and trivially initialized classes
PreCompile(class_loader, dex_files, timings);
+ if (IsBootImage()) {
+ // We don't need to setup the intrinsics for non boot image compilation, as
+ // those compilations will pick up a boot image that have the ArtMethod already
+ // set with the intrinsics flag.
+ ScopedObjectAccess soa(Thread::Current());
+#define OPTIMIZING_INTRINSICS(Name, InvokeType, NeedsEnvironmentOrCache, SideEffects, Exceptions, ClassName, MethodName, Signature) \
+ SetupIntrinsic(soa.Self(), Intrinsics::k##Name, InvokeType, ClassName, MethodName, Signature);
+#include "intrinsics_list.h"
+INTRINSICS_LIST(OPTIMIZING_INTRINSICS)
+#undef INTRINSICS_LIST
+ }
// Compile:
// 1) Compile all classes and methods enabled for compilation. May fall back to dex-to-dex
// compilation.
@@ -535,7 +565,7 @@
ScopedObjectAccess soa(self);
StackHandleScope<1> hs(soa.Self());
Handle<mirror::ClassLoader> class_loader(
- hs.NewHandle(soa.Decode<mirror::ClassLoader*>(jclass_loader)));
+ hs.NewHandle(soa.Decode<mirror::ClassLoader>(jclass_loader)));
return GetDexToDexCompilationLevel(self, driver, class_loader, dex_file, class_def);
}
@@ -610,7 +640,7 @@
ScopedObjectAccess soa(self);
StackHandleScope<1> hs(soa.Self());
Handle<mirror::ClassLoader> class_loader_handle(hs.NewHandle(
- soa.Decode<mirror::ClassLoader*>(class_loader)));
+ soa.Decode<mirror::ClassLoader>(class_loader)));
// TODO: Lookup annotation from DexFile directly without resolving method.
ArtMethod* method =
@@ -1626,7 +1656,7 @@
{
StackHandleScope<1> hs(soa.Self());
Handle<mirror::ClassLoader> class_loader_handle(
- hs.NewHandle(soa.Decode<mirror::ClassLoader*>(mUnit->GetClassLoader())));
+ hs.NewHandle(soa.Decode<mirror::ClassLoader>(mUnit->GetClassLoader())));
resolved_field = ResolveField(soa, dex_cache, class_loader_handle, mUnit, field_idx, false);
referrer_class = resolved_field != nullptr
? ResolveCompilingMethodsClass(soa, dex_cache, class_loader_handle, mUnit) : nullptr;
@@ -1970,7 +2000,7 @@
ScopedObjectAccess soa(self);
StackHandleScope<2> hs(soa.Self());
Handle<mirror::ClassLoader> class_loader(
- hs.NewHandle(soa.Decode<mirror::ClassLoader*>(jclass_loader)));
+ hs.NewHandle(soa.Decode<mirror::ClassLoader>(jclass_loader)));
Handle<mirror::DexCache> dex_cache(hs.NewHandle(class_linker->FindDexCache(
soa.Self(), dex_file, false)));
// Resolve the class.
@@ -2067,7 +2097,7 @@
const DexFile& dex_file = *manager_->GetDexFile();
StackHandleScope<2> hs(soa.Self());
Handle<mirror::ClassLoader> class_loader(
- hs.NewHandle(soa.Decode<mirror::ClassLoader*>(manager_->GetClassLoader())));
+ hs.NewHandle(soa.Decode<mirror::ClassLoader>(manager_->GetClassLoader())));
Handle<mirror::DexCache> dex_cache(hs.NewHandle(class_linker->RegisterDexFile(
dex_file,
class_loader.Get())));
@@ -2166,7 +2196,7 @@
jobject jclass_loader = manager_->GetClassLoader();
StackHandleScope<3> hs(soa.Self());
Handle<mirror::ClassLoader> class_loader(
- hs.NewHandle(soa.Decode<mirror::ClassLoader*>(jclass_loader)));
+ hs.NewHandle(soa.Decode<mirror::ClassLoader>(jclass_loader)));
Handle<mirror::Class> klass(
hs.NewHandle(class_linker->FindClass(soa.Self(), descriptor, class_loader)));
if (klass.Get() == nullptr) {
@@ -2254,7 +2284,7 @@
jobject jclass_loader = manager_->GetClassLoader();
StackHandleScope<3> hs(soa.Self());
Handle<mirror::ClassLoader> class_loader(
- hs.NewHandle(soa.Decode<mirror::ClassLoader*>(jclass_loader)));
+ hs.NewHandle(soa.Decode<mirror::ClassLoader>(jclass_loader)));
Handle<mirror::Class> klass(
hs.NewHandle(class_linker->FindClass(soa.Self(), descriptor, class_loader)));
// Class might have failed resolution. Then don't set it to verified.
@@ -2316,7 +2346,7 @@
ScopedObjectAccess soa(Thread::Current());
StackHandleScope<3> hs(soa.Self());
Handle<mirror::ClassLoader> class_loader(
- hs.NewHandle(soa.Decode<mirror::ClassLoader*>(jclass_loader)));
+ hs.NewHandle(soa.Decode<mirror::ClassLoader>(jclass_loader)));
Handle<mirror::Class> klass(
hs.NewHandle(manager_->GetClassLinker()->FindClass(soa.Self(), descriptor, class_loader)));
@@ -2551,7 +2581,7 @@
ScopedObjectAccess soa(Thread::Current());
StackHandleScope<3> hs(soa.Self());
Handle<mirror::ClassLoader> class_loader(
- hs.NewHandle(soa.Decode<mirror::ClassLoader*>(jclass_loader)));
+ hs.NewHandle(soa.Decode<mirror::ClassLoader>(jclass_loader)));
Handle<mirror::Class> klass(
hs.NewHandle(class_linker->FindClass(soa.Self(), descriptor, class_loader)));
Handle<mirror::DexCache> dex_cache;
diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h
index 41f0d36..52a04cc 100644
--- a/compiler/driver/compiler_driver.h
+++ b/compiler/driver/compiler_driver.h
@@ -57,7 +57,6 @@
class CompiledMethod;
class CompilerOptions;
class DexCompilationUnit;
-class DexFileToMethodInlinerMap;
struct InlineIGetIPutData;
class InstructionSetFeatures;
class ParallelCompilationManager;
@@ -88,7 +87,6 @@
// classes.
CompilerDriver(const CompilerOptions* compiler_options,
VerificationResults* verification_results,
- DexFileToMethodInlinerMap* method_inliner_map,
Compiler::Kind compiler_kind,
InstructionSet instruction_set,
const InstructionSetFeatures* instruction_set_features,
@@ -133,10 +131,6 @@
return verification_results_;
}
- DexFileToMethodInlinerMap* GetMethodInlinerMap() const {
- return method_inliner_map_;
- }
-
InstructionSet GetInstructionSet() const {
return instruction_set_;
}
@@ -603,7 +597,6 @@
const CompilerOptions* const compiler_options_;
VerificationResults* const verification_results_;
- DexFileToMethodInlinerMap* const method_inliner_map_;
std::unique_ptr<Compiler> compiler_;
Compiler::Kind compiler_kind_;
diff --git a/compiler/driver/compiler_driver_test.cc b/compiler/driver/compiler_driver_test.cc
index b9a5a78..96f17ac 100644
--- a/compiler/driver/compiler_driver_test.cc
+++ b/compiler/driver/compiler_driver_test.cc
@@ -32,7 +32,7 @@
#include "mirror/object-inl.h"
#include "handle_scope-inl.h"
#include "jit/offline_profiling_info.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
namespace art {
@@ -83,7 +83,7 @@
ScopedObjectAccess soa(Thread::Current());
StackHandleScope<1> hs(soa.Self());
Handle<mirror::ClassLoader> loader(
- hs.NewHandle(soa.Decode<mirror::ClassLoader*>(class_loader)));
+ hs.NewHandle(soa.Decode<mirror::ClassLoader>(class_loader)));
mirror::Class* c = class_linker->FindClass(soa.Self(), descriptor, loader);
CHECK(c != nullptr);
const auto pointer_size = class_linker->GetImagePointerSize();
diff --git a/compiler/elf_writer.cc b/compiler/elf_writer.cc
index ca0869a..0c06090 100644
--- a/compiler/elf_writer.cc
+++ b/compiler/elf_writer.cc
@@ -26,7 +26,7 @@
#include "invoke_type.h"
#include "mirror/object-inl.h"
#include "oat.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
namespace art {
diff --git a/compiler/exception_test.cc b/compiler/exception_test.cc
index 86f91c5..f9e5cb9 100644
--- a/compiler/exception_test.cc
+++ b/compiler/exception_test.cc
@@ -31,7 +31,7 @@
#include "oat_quick_method_header.h"
#include "optimizing/stack_map_stream.h"
#include "runtime.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
#include "handle_scope-inl.h"
#include "thread.h"
@@ -45,7 +45,7 @@
ScopedObjectAccess soa(Thread::Current());
StackHandleScope<2> hs(soa.Self());
Handle<mirror::ClassLoader> class_loader(
- hs.NewHandle(soa.Decode<mirror::ClassLoader*>(LoadDex("ExceptionHandle"))));
+ hs.NewHandle(soa.Decode<mirror::ClassLoader>(LoadDex("ExceptionHandle"))));
my_klass_ = class_linker_->FindClass(soa.Self(), "LExceptionHandle;", class_loader);
ASSERT_TRUE(my_klass_ != nullptr);
Handle<mirror::Class> klass(hs.NewHandle(my_klass_));
@@ -219,7 +219,7 @@
ASSERT_TRUE(internal != nullptr);
jobjectArray ste_array = Thread::InternalStackTraceToStackTraceElementArray(soa, internal);
ASSERT_TRUE(ste_array != nullptr);
- auto* trace_array = soa.Decode<mirror::ObjectArray<mirror::StackTraceElement>*>(ste_array);
+ auto trace_array = soa.Decode<mirror::ObjectArray<mirror::StackTraceElement>>(ste_array);
ASSERT_TRUE(trace_array != nullptr);
ASSERT_TRUE(trace_array->Get(0) != nullptr);
diff --git a/compiler/image_test.cc b/compiler/image_test.cc
index ea4b7ee..4689c9d 100644
--- a/compiler/image_test.cc
+++ b/compiler/image_test.cc
@@ -33,7 +33,7 @@
#include "lock_word.h"
#include "mirror/object-inl.h"
#include "oat_writer.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
#include "signal_catcher.h"
#include "utils.h"
diff --git a/compiler/image_writer.cc b/compiler/image_writer.cc
index 6b5758b..41bda60 100644
--- a/compiler/image_writer.cc
+++ b/compiler/image_writer.cc
@@ -63,7 +63,7 @@
#include "oat_file.h"
#include "oat_file_manager.h"
#include "runtime.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
#include "handle_scope-inl.h"
#include "utils/dex_cache_arrays_layout-inl.h"
diff --git a/compiler/intrinsics_enum.h b/compiler/intrinsics_enum.h
new file mode 100644
index 0000000..5528181
--- /dev/null
+++ b/compiler/intrinsics_enum.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_COMPILER_INTRINSICS_ENUM_H_
+#define ART_COMPILER_INTRINSICS_ENUM_H_
+
+namespace art {
+
+enum class Intrinsics {
+#define OPTIMIZING_INTRINSICS(Name, ...) \
+ k ## Name,
+#include "intrinsics_list.h"
+ kNone,
+ INTRINSICS_LIST(OPTIMIZING_INTRINSICS)
+#undef INTRINSICS_LIST
+#undef OPTIMIZING_INTRINSICS
+};
+std::ostream& operator<<(std::ostream& os, const Intrinsics& intrinsic);
+
+} // namespace art
+
+#endif // ART_COMPILER_INTRINSICS_ENUM_H_
diff --git a/compiler/intrinsics_list.h b/compiler/intrinsics_list.h
new file mode 100644
index 0000000..5877f57
--- /dev/null
+++ b/compiler/intrinsics_list.h
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C, "", "", "") 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License", "", "", "");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_COMPILER_INTRINSICS_LIST_H_
+#define ART_COMPILER_INTRINSICS_LIST_H_
+
+// All intrinsics supported by ART. Format is name, then whether it is expected
+// to be a HInvokeStaticOrDirect node (compared to HInvokeVirtual), then whether it requires an
+// environment, may have side effects, or may throw exceptions.
+
+// Note: adding a new intrinsic requires an art image version change,
+// as the modifiers flag for some ArtMethods will need to be changed.
+
+#define INTRINSICS_LIST(V) \
+ V(DoubleDoubleToRawLongBits, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Double;", "doubleToRawLongBits", "(D)J") \
+ V(DoubleDoubleToLongBits, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Double;", "doubleToLongBits", "(D)J") \
+ V(DoubleIsInfinite, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Double;", "isInfinite", "(D)Z") \
+ V(DoubleIsNaN, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Double;", "isNaN", "(D)Z") \
+ V(DoubleLongBitsToDouble, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Double;", "longBitsToDouble", "(J)D") \
+ V(FloatFloatToRawIntBits, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Float;", "floatToRawIntBits", "(F)I") \
+ V(FloatFloatToIntBits, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Float;", "floatToIntBits", "(F)I") \
+ V(FloatIsInfinite, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Float;", "isInfinite", "(F)Z") \
+ V(FloatIsNaN, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Float;", "isNaN", "(F)Z") \
+ V(FloatIntBitsToFloat, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Float;", "intBitsToFloat", "(I)F") \
+ V(IntegerReverse, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Integer;", "reverse", "(I)I") \
+ V(IntegerReverseBytes, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Integer;", "reverseBytes", "(I)I") \
+ V(IntegerBitCount, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Integer;", "bitCount", "(I)I") \
+ V(IntegerCompare, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Integer;", "compare", "(II)I") \
+ V(IntegerHighestOneBit, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Integer;", "highestOneBit", "(I)I") \
+ V(IntegerLowestOneBit, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Integer;", "lowestOneBit", "(I)I") \
+ V(IntegerNumberOfLeadingZeros, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Integer;", "numberOfLeadingZeros", "(I)I") \
+ V(IntegerNumberOfTrailingZeros, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Integer;", "numberOfTrailingZeros", "(I)I") \
+ V(IntegerRotateRight, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Integer;", "rotateRight", "(II)I") \
+ V(IntegerRotateLeft, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Integer;", "rotateLeft", "(II)I") \
+ V(IntegerSignum, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Integer;", "signum", "(I)I") \
+ V(LongReverse, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Long;", "reverse", "(J)J") \
+ V(LongReverseBytes, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Long;", "reverseBytes", "(J)J") \
+ V(LongBitCount, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Long;", "bitCount", "(J)I") \
+ V(LongCompare, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Long;", "compare", "(JJ)I") \
+ V(LongHighestOneBit, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Long;", "highestOneBit", "(J)J") \
+ V(LongLowestOneBit, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Long;", "lowestOneBit", "(J)J") \
+ V(LongNumberOfLeadingZeros, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Long;", "numberOfLeadingZeros", "(J)I") \
+ V(LongNumberOfTrailingZeros, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Long;", "numberOfTrailingZeros", "(J)I") \
+ V(LongRotateRight, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Long;", "rotateRight", "(JI)J") \
+ V(LongRotateLeft, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Long;", "rotateLeft", "(JI)J") \
+ V(LongSignum, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Long;", "signum", "(J)I") \
+ V(ShortReverseBytes, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Short;", "reverseBytes", "(S)S") \
+ V(MathAbsDouble, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Math;", "abs", "(D)D") \
+ V(MathAbsFloat, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Math;", "abs", "(F)F") \
+ V(MathAbsLong, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Math;", "abs", "(J)J") \
+ V(MathAbsInt, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Math;", "abs", "(I)I") \
+ V(MathMinDoubleDouble, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Math;", "min", "(DD)D") \
+ V(MathMinFloatFloat, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Math;", "min", "(FF)F") \
+ V(MathMinLongLong, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Math;", "min", "(JJ)J") \
+ V(MathMinIntInt, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Math;", "min", "(II)I") \
+ V(MathMaxDoubleDouble, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Math;", "max", "(DD)D") \
+ V(MathMaxFloatFloat, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Math;", "max", "(FF)F") \
+ V(MathMaxLongLong, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Math;", "max", "(JJ)J") \
+ V(MathMaxIntInt, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Math;", "max", "(II)I") \
+ V(MathCos, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Math;", "cos", "(D)D") \
+ V(MathSin, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Math;", "sin", "(D)D") \
+ V(MathAcos, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Math;", "acos", "(D)D") \
+ V(MathAsin, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Math;", "asin", "(D)D") \
+ V(MathAtan, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Math;", "atan", "(D)D") \
+ V(MathAtan2, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Math;", "atan2", "(DD)D") \
+ V(MathCbrt, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Math;", "cbrt", "(D)D") \
+ V(MathCosh, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Math;", "cosh", "(D)D") \
+ V(MathExp, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Math;", "exp", "(D)D") \
+ V(MathExpm1, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Math;", "expm1", "(D)D") \
+ V(MathHypot, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Math;", "hypot", "(DD)D") \
+ V(MathLog, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Math;", "log", "(D)D") \
+ V(MathLog10, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Math;", "log10", "(D)D") \
+ V(MathNextAfter, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Math;", "nextAfter", "(DD)D") \
+ V(MathSinh, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Math;", "sinh", "(D)D") \
+ V(MathTan, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Math;", "tan", "(D)D") \
+ V(MathTanh, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Math;", "tanh", "(D)D") \
+ V(MathSqrt, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Math;", "sqrt", "(D)D") \
+ V(MathCeil, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Math;", "ceil", "(D)D") \
+ V(MathFloor, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Math;", "floor", "(D)D") \
+ V(MathRint, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Math;", "rint", "(D)D") \
+ V(MathRoundDouble, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Math;", "round", "(D)J") \
+ V(MathRoundFloat, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Math;", "round", "(F)I") \
+ V(SystemArrayCopyChar, kStatic, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow, "Ljava/lang/System;", "arraycopy", "([CI[CII)V") \
+ V(SystemArrayCopy, kStatic, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow, "Ljava/lang/System;", "arraycopy", "(Ljava/lang/Object;ILjava/lang/Object;II)V") \
+ V(ThreadCurrentThread, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow, "Ljava/lang/Thread;", "currentThread", "()Ljava/lang/Thread;") \
+ V(MemoryPeekByte, kStatic, kNeedsEnvironmentOrCache, kReadSideEffects, kCanThrow, "Llibcore/io/Memory;", "peekByte", "(J)B") \
+ V(MemoryPeekIntNative, kStatic, kNeedsEnvironmentOrCache, kReadSideEffects, kCanThrow, "Llibcore/io/Memory;", "peekIntNative", "(J)I") \
+ V(MemoryPeekLongNative, kStatic, kNeedsEnvironmentOrCache, kReadSideEffects, kCanThrow, "Llibcore/io/Memory;", "peekLongNative", "(J)J") \
+ V(MemoryPeekShortNative, kStatic, kNeedsEnvironmentOrCache, kReadSideEffects, kCanThrow, "Llibcore/io/Memory;", "peekShortNative", "(J)S") \
+ V(MemoryPokeByte, kStatic, kNeedsEnvironmentOrCache, kWriteSideEffects, kCanThrow, "Llibcore/io/Memory;", "pokeByte", "(JB)V") \
+ V(MemoryPokeIntNative, kStatic, kNeedsEnvironmentOrCache, kWriteSideEffects, kCanThrow, "Llibcore/io/Memory;", "pokeIntNative", "(JI)V") \
+ V(MemoryPokeLongNative, kStatic, kNeedsEnvironmentOrCache, kWriteSideEffects, kCanThrow, "Llibcore/io/Memory;", "pokeLongNative", "(JJ)V") \
+ V(MemoryPokeShortNative, kStatic, kNeedsEnvironmentOrCache, kWriteSideEffects, kCanThrow, "Llibcore/io/Memory;", "pokeShortNative", "(JS)V") \
+ V(StringCharAt, kVirtual, kNeedsEnvironmentOrCache, kReadSideEffects, kCanThrow, "Ljava/lang/String;", "charAt", "(I)C") \
+ V(StringCompareTo, kVirtual, kNeedsEnvironmentOrCache, kReadSideEffects, kCanThrow, "Ljava/lang/String;", "compareTo", "(Ljava/lang/String;)I") \
+ V(StringEquals, kVirtual, kNeedsEnvironmentOrCache, kReadSideEffects, kCanThrow, "Ljava/lang/String;", "equals", "(Ljava/lang/Object;)Z") \
+ V(StringGetCharsNoCheck, kVirtual, kNeedsEnvironmentOrCache, kReadSideEffects, kCanThrow, "Ljava/lang/String;", "getCharsNoCheck", "(II[CI)V") \
+ V(StringIndexOf, kVirtual, kNeedsEnvironmentOrCache, kReadSideEffects, kCanThrow, "Ljava/lang/String;", "indexOf", "(I)I") \
+ V(StringIndexOfAfter, kVirtual, kNeedsEnvironmentOrCache, kReadSideEffects, kCanThrow, "Ljava/lang/String;", "indexOf", "(II)I") \
+ V(StringIsEmpty, kVirtual, kNeedsEnvironmentOrCache, kReadSideEffects, kNoThrow, "Ljava/lang/String;", "isEmpty", "()Z") \
+ V(StringLength, kVirtual, kNeedsEnvironmentOrCache, kReadSideEffects, kNoThrow, "Ljava/lang/String;", "length", "()I") \
+ V(StringNewStringFromBytes, kStatic, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow, "Ljava/lang/StringFactory;", "newStringFromBytes", "([BIII)Ljava/lang/String;") \
+ V(StringNewStringFromChars, kStatic, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow, "Ljava/lang/StringFactory;", "newStringFromChars", "(II[C)Ljava/lang/String;") \
+ V(StringNewStringFromString, kStatic, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow, "Ljava/lang/StringFactory;", "newStringFromString", "(Ljava/lang/String;)Ljava/lang/String;") \
+ V(UnsafeCASInt, kVirtual, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow, "Lsun/misc/Unsafe;", "compareAndSwapInt", "(Ljava/lang/Object;JII)Z") \
+ V(UnsafeCASLong, kVirtual, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow, "Lsun/misc/Unsafe;", "compareAndSwapLong", "(Ljava/lang/Object;JJJ)Z") \
+ V(UnsafeCASObject, kVirtual, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow, "Lsun/misc/Unsafe;", "compareAndSwapObject", "(Ljava/lang/Object;JLjava/lang/Object;Ljava/lang/Object;)Z") \
+ V(UnsafeGet, kVirtual, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow, "Lsun/misc/Unsafe;", "getInt", "(Ljava/lang/Object;J)I") \
+ V(UnsafeGetVolatile, kVirtual, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow, "Lsun/misc/Unsafe;", "getIntVolatile", "(Ljava/lang/Object;J)I") \
+ V(UnsafeGetObject, kVirtual, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow, "Lsun/misc/Unsafe;", "getObject", "(Ljava/lang/Object;J)Ljava/lang/Object;") \
+ V(UnsafeGetObjectVolatile, kVirtual, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow, "Lsun/misc/Unsafe;", "getObjectVolatile", "(Ljava/lang/Object;J)Ljava/lang/Object;") \
+ V(UnsafeGetLong, kVirtual, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow, "Lsun/misc/Unsafe;", "getLong", "(Ljava/lang/Object;J)J") \
+ V(UnsafeGetLongVolatile, kVirtual, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow, "Lsun/misc/Unsafe;", "getLongVolatile", "(Ljava/lang/Object;J)J") \
+ V(UnsafePut, kVirtual, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow, "Lsun/misc/Unsafe;", "putInt", "(Ljava/lang/Object;JI)V") \
+ V(UnsafePutOrdered, kVirtual, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow, "Lsun/misc/Unsafe;", "putOrderedInt", "(Ljava/lang/Object;JI)V") \
+ V(UnsafePutVolatile, kVirtual, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow, "Lsun/misc/Unsafe;", "putIntVolatile", "(Ljava/lang/Object;JI)V") \
+ V(UnsafePutObject, kVirtual, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow, "Lsun/misc/Unsafe;", "putObject", "(Ljava/lang/Object;JLjava/lang/Object;)V") \
+ V(UnsafePutObjectOrdered, kVirtual, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow, "Lsun/misc/Unsafe;", "putOrderedObject", "(Ljava/lang/Object;JLjava/lang/Object;)V") \
+ V(UnsafePutObjectVolatile, kVirtual, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow, "Lsun/misc/Unsafe;", "putObjectVolatile", "(Ljava/lang/Object;JLjava/lang/Object;)V") \
+ V(UnsafePutLong, kVirtual, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow, "Lsun/misc/Unsafe;", "putLong", "(Ljava/lang/Object;JJ)V") \
+ V(UnsafePutLongOrdered, kVirtual, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow, "Lsun/misc/Unsafe;", "putOrderedLong", "(Ljava/lang/Object;JJ)V") \
+ V(UnsafePutLongVolatile, kVirtual, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow, "Lsun/misc/Unsafe;", "putLongVolatile", "(Ljava/lang/Object;JJ)V") \
+ V(UnsafeGetAndAddInt, kVirtual, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow, "Lsun/misc/Unsafe;", "getAndAddInt", "(Ljava/lang/Object;JI)I") \
+ V(UnsafeGetAndAddLong, kVirtual, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow, "Lsun/misc/Unsafe;", "getAndAddLong", "(Ljava/lang/Object;JJ)J") \
+ V(UnsafeGetAndSetInt, kVirtual, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow, "Lsun/misc/Unsafe;", "getAndSetInt", "(Ljava/lang/Object;JI)I") \
+ V(UnsafeGetAndSetLong, kVirtual, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow, "Lsun/misc/Unsafe;", "getAndSetLong", "(Ljava/lang/Object;JJ)J") \
+ V(UnsafeGetAndSetObject, kVirtual, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow, "Lsun/misc/Unsafe;", "getAndSetObject", "(Ljava/lang/Object;JLjava/lang/Object;)Ljava/lang/Object;") \
+ V(UnsafeLoadFence, kVirtual, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow, "Lsun/misc/Unsafe;", "loadFence", "()V") \
+ V(UnsafeStoreFence, kVirtual, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow, "Lsun/misc/Unsafe;", "storeFence", "()V") \
+ V(UnsafeFullFence, kVirtual, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow, "Lsun/misc/Unsafe;", "fullFence", "()V") \
+ V(ReferenceGetReferent, kDirect, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow, "Ljava/lang/ref/Reference;", "getReferent", "()Ljava/lang/Object;")
+
+#endif // ART_COMPILER_INTRINSICS_LIST_H_
+#undef ART_COMPILER_INTRINSICS_LIST_H_ // #define is only for lint.
diff --git a/compiler/jit/jit_compiler.cc b/compiler/jit/jit_compiler.cc
index 7246ace..4f86905 100644
--- a/compiler/jit/jit_compiler.cc
+++ b/compiler/jit/jit_compiler.cc
@@ -150,11 +150,9 @@
instruction_set_features_.reset(InstructionSetFeatures::FromCppDefines());
}
cumulative_logger_.reset(new CumulativeLogger("jit times"));
- method_inliner_map_.reset(new DexFileToMethodInlinerMap);
compiler_driver_.reset(new CompilerDriver(
compiler_options_.get(),
/* verification_results */ nullptr,
- method_inliner_map_.get(),
Compiler::kOptimizing,
instruction_set,
instruction_set_features_.get(),
diff --git a/compiler/jit/jit_compiler.h b/compiler/jit/jit_compiler.h
index 18e3155..ea2747c 100644
--- a/compiler/jit/jit_compiler.h
+++ b/compiler/jit/jit_compiler.h
@@ -19,7 +19,6 @@
#include "base/mutex.h"
#include "compiled_method.h"
-#include "dex/quick/dex_file_to_method_inliner_map.h"
#include "driver/compiler_driver.h"
#include "driver/compiler_options.h"
@@ -49,7 +48,6 @@
private:
std::unique_ptr<CompilerOptions> compiler_options_;
std::unique_ptr<CumulativeLogger> cumulative_logger_;
- std::unique_ptr<DexFileToMethodInlinerMap> method_inliner_map_;
std::unique_ptr<CompilerDriver> compiler_driver_;
std::unique_ptr<const InstructionSetFeatures> instruction_set_features_;
std::unique_ptr<File> perf_file_;
diff --git a/compiler/jni/jni_compiler_test.cc b/compiler/jni/jni_compiler_test.cc
index b692c6d..19d55a3 100644
--- a/compiler/jni/jni_compiler_test.cc
+++ b/compiler/jni/jni_compiler_test.cc
@@ -36,7 +36,7 @@
#include "nativeloader/native_loader.h"
#include "runtime.h"
#include "ScopedLocalRef.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
#include "thread.h"
extern "C" JNIEXPORT jint JNICALL Java_MyClassNatives_bar(JNIEnv*, jobject, jint count) {
@@ -238,7 +238,7 @@
ScopedObjectAccess soa(Thread::Current());
StackHandleScope<1> hs(soa.Self());
Handle<mirror::ClassLoader> loader(
- hs.NewHandle(soa.Decode<mirror::ClassLoader*>(class_loader)));
+ hs.NewHandle(soa.Decode<mirror::ClassLoader>(class_loader)));
// Compile the native method before starting the runtime
mirror::Class* c = class_linker_->FindClass(soa.Self(), "LMyClassNatives;", loader);
const auto pointer_size = class_linker_->GetImagePointerSize();
@@ -431,6 +431,7 @@
TEST_F(JniCompilerTest, TestName ## CriticalGeneric) { \
SCOPED_TRACE("@CriticalNative JNI with generic"); \
gCurrentJni = static_cast<uint32_t>(JniKind::kCritical); \
+ SetCheckGenericJni(true); \
TestName ## Impl(); \
}
@@ -1139,8 +1140,8 @@
// Build stack trace
jobject internal = Thread::Current()->CreateInternalStackTrace<false>(soa);
jobjectArray ste_array = Thread::InternalStackTraceToStackTraceElementArray(soa, internal);
- mirror::ObjectArray<mirror::StackTraceElement>* trace_array =
- soa.Decode<mirror::ObjectArray<mirror::StackTraceElement>*>(ste_array);
+ ObjPtr<mirror::ObjectArray<mirror::StackTraceElement>> trace_array =
+ soa.Decode<mirror::ObjectArray<mirror::StackTraceElement>>(ste_array);
EXPECT_TRUE(trace_array != nullptr);
EXPECT_EQ(11, trace_array->GetLength());
@@ -1204,7 +1205,7 @@
// Add 10 local references
ScopedObjectAccess soa(env);
for (int i = 0; i < 10; i++) {
- soa.AddLocalReference<jobject>(soa.Decode<mirror::Object*>(thisObj));
+ soa.AddLocalReference<jobject>(soa.Decode<mirror::Object>(thisObj));
}
return x+1;
}
@@ -1282,7 +1283,7 @@
Thread* self = Thread::Current();
ScopedObjectAccess soa(self);
- EXPECT_TRUE(self->HoldsLock(soa.Decode<mirror::Object*>(thisObj)));
+ EXPECT_TRUE(self->HoldsLock(soa.Decode<mirror::Object>(thisObj).Decode()));
return nullptr;
}
diff --git a/compiler/linker/relative_patcher_test.h b/compiler/linker/relative_patcher_test.h
index 304b31c..62b3a0a 100644
--- a/compiler/linker/relative_patcher_test.h
+++ b/compiler/linker/relative_patcher_test.h
@@ -22,7 +22,6 @@
#include "base/array_ref.h"
#include "base/macros.h"
#include "compiled_method.h"
-#include "dex/quick/dex_file_to_method_inliner_map.h"
#include "dex/verification_results.h"
#include "driver/compiler_driver.h"
#include "driver/compiler_options.h"
@@ -43,10 +42,8 @@
RelativePatcherTest(InstructionSet instruction_set, const std::string& variant)
: compiler_options_(),
verification_results_(&compiler_options_),
- inliner_map_(),
driver_(&compiler_options_,
&verification_results_,
- &inliner_map_,
Compiler::kQuick,
instruction_set,
/* instruction_set_features*/ nullptr,
@@ -269,7 +266,6 @@
CompilerOptions compiler_options_;
VerificationResults verification_results_;
- DexFileToMethodInlinerMap inliner_map_;
CompilerDriver driver_; // Needed for constructing CompiledMethod.
std::string error_msg_;
InstructionSet instruction_set_;
diff --git a/compiler/oat_test.cc b/compiler/oat_test.cc
index 24d102d..e8bc67d 100644
--- a/compiler/oat_test.cc
+++ b/compiler/oat_test.cc
@@ -23,7 +23,6 @@
#include "compiled_method.h"
#include "compiler.h"
#include "debug/method_debug_info.h"
-#include "dex/quick/dex_file_to_method_inliner_map.h"
#include "dex/quick_compiler_callbacks.h"
#include "dex/verification_results.h"
#include "driver/compiler_driver.h"
@@ -38,7 +37,7 @@
#include "mirror/object_array-inl.h"
#include "oat_file-inl.h"
#include "oat_writer.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
#include "utils/test_dex_file_builder.h"
namespace art {
@@ -100,15 +99,12 @@
compiler_options_->ParseCompilerOption(option, Usage);
}
verification_results_.reset(new VerificationResults(compiler_options_.get()));
- method_inliner_map_.reset(new DexFileToMethodInlinerMap);
callbacks_.reset(new QuickCompilerCallbacks(verification_results_.get(),
- method_inliner_map_.get(),
CompilerCallbacks::CallbackMode::kCompileApp));
Runtime::Current()->SetCompilerCallbacks(callbacks_.get());
timer_.reset(new CumulativeLogger("Compilation times"));
compiler_driver_.reset(new CompilerDriver(compiler_options_.get(),
verification_results_.get(),
- method_inliner_map_.get(),
compiler_kind,
insn_set,
insn_features_.get(),
@@ -501,7 +497,8 @@
ClassLinker* const class_linker = Runtime::Current()->GetClassLinker();
for (const DexFile* dex_file : dex_files) {
ScopedObjectAccess soa(Thread::Current());
- class_linker->RegisterDexFile(*dex_file, soa.Decode<mirror::ClassLoader*>(class_loader));
+ class_linker->RegisterDexFile(*dex_file,
+ soa.Decode<mirror::ClassLoader>(class_loader).Decode());
}
compiler_driver_->SetDexFilesForOatFile(dex_files);
compiler_driver_->CompileAll(class_loader, dex_files, &timings);
diff --git a/compiler/oat_writer.cc b/compiler/oat_writer.cc
index c840a9e..54ec7c1 100644
--- a/compiler/oat_writer.cc
+++ b/compiler/oat_writer.cc
@@ -50,7 +50,7 @@
#include "oat_quick_method_header.h"
#include "os.h"
#include "safe_map.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
#include "type_lookup_table.h"
#include "utils/dex_cache_arrays_layout-inl.h"
#include "vdex_file.h"
diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc
index 55e1221..681988d 100644
--- a/compiler/optimizing/code_generator_arm.cc
+++ b/compiler/optimizing/code_generator_arm.cc
@@ -4589,7 +4589,9 @@
}
// We need a temporary register for the read barrier marking slow
// path in CodeGeneratorARM::GenerateArrayLoadWithBakerReadBarrier.
- if (object_array_get_with_read_barrier && kUseBakerReadBarrier) {
+ // Also need for String compression feature.
+ if ((object_array_get_with_read_barrier && kUseBakerReadBarrier)
+ || (mirror::kUseStringCompression && instruction->IsStringCharAt())) {
locations->AddTemp(Location::RequiresRegister());
}
}
@@ -4602,6 +4604,8 @@
Location out_loc = locations->Out();
uint32_t data_offset = CodeGenerator::GetArrayDataOffset(instruction);
Primitive::Type type = instruction->GetType();
+ const bool maybe_compressed_char_at = mirror::kUseStringCompression &&
+ instruction->IsStringCharAt();
HInstruction* array_instr = instruction->GetArray();
bool has_intermediate_address = array_instr->IsIntermediateAddress();
// The read barrier instrumentation does not support the HIntermediateAddress instruction yet.
@@ -4615,10 +4619,31 @@
case Primitive::kPrimInt: {
if (index.IsConstant()) {
int32_t const_index = index.GetConstant()->AsIntConstant()->GetValue();
- uint32_t full_offset = data_offset + (const_index << Primitive::ComponentSizeShift(type));
+ if (maybe_compressed_char_at) {
+ Register length = IP;
+ Label uncompressed_load, done;
+ uint32_t count_offset = mirror::String::CountOffset().Uint32Value();
+ __ LoadFromOffset(kLoadWord, length, obj, count_offset);
+ codegen_->MaybeRecordImplicitNullCheck(instruction);
+ __ cmp(length, ShifterOperand(0));
+ __ b(&uncompressed_load, GE);
+ __ LoadFromOffset(kLoadUnsignedByte,
+ out_loc.AsRegister<Register>(),
+ obj,
+ data_offset + const_index);
+ __ b(&done);
+ __ Bind(&uncompressed_load);
+ __ LoadFromOffset(GetLoadOperandType(Primitive::kPrimChar),
+ out_loc.AsRegister<Register>(),
+ obj,
+ data_offset + (const_index << 1));
+ __ Bind(&done);
+ } else {
+ uint32_t full_offset = data_offset + (const_index << Primitive::ComponentSizeShift(type));
- LoadOperandType load_type = GetLoadOperandType(type);
- __ LoadFromOffset(load_type, out_loc.AsRegister<Register>(), obj, full_offset);
+ LoadOperandType load_type = GetLoadOperandType(type);
+ __ LoadFromOffset(load_type, out_loc.AsRegister<Register>(), obj, full_offset);
+ }
} else {
Register temp = IP;
@@ -4634,7 +4659,24 @@
} else {
__ add(temp, obj, ShifterOperand(data_offset));
}
- codegen_->LoadFromShiftedRegOffset(type, out_loc, temp, index.AsRegister<Register>());
+ if (maybe_compressed_char_at) {
+ Label uncompressed_load, done;
+ uint32_t count_offset = mirror::String::CountOffset().Uint32Value();
+ Register length = locations->GetTemp(0).AsRegister<Register>();
+ __ LoadFromOffset(kLoadWord, length, obj, count_offset);
+ codegen_->MaybeRecordImplicitNullCheck(instruction);
+ __ cmp(length, ShifterOperand(0));
+ __ b(&uncompressed_load, GE);
+ __ ldrb(out_loc.AsRegister<Register>(),
+ Address(temp, index.AsRegister<Register>(), Shift::LSL, 0));
+ __ b(&done);
+ __ Bind(&uncompressed_load);
+ __ ldrh(out_loc.AsRegister<Register>(),
+ Address(temp, index.AsRegister<Register>(), Shift::LSL, 1));
+ __ Bind(&done);
+ } else {
+ codegen_->LoadFromShiftedRegOffset(type, out_loc, temp, index.AsRegister<Register>());
+ }
}
break;
}
@@ -4734,7 +4776,7 @@
if (type == Primitive::kPrimNot) {
// Potential implicit null checks, in the case of reference
// arrays, are handled in the previous switch statement.
- } else {
+ } else if (!maybe_compressed_char_at) {
codegen_->MaybeRecordImplicitNullCheck(instruction);
}
}
@@ -5024,6 +5066,10 @@
Register out = locations->Out().AsRegister<Register>();
__ LoadFromOffset(kLoadWord, out, obj, offset);
codegen_->MaybeRecordImplicitNullCheck(instruction);
+ // Mask out compression flag from String's array length.
+ if (mirror::kUseStringCompression && instruction->IsStringLength()) {
+ __ bic(out, out, ShifterOperand(1u << 31));
+ }
}
void LocationsBuilderARM::VisitIntermediateAddress(HIntermediateAddress* instruction) {
diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc
index a2a2e42..4f7f36b 100644
--- a/compiler/optimizing/code_generator_arm64.cc
+++ b/compiler/optimizing/code_generator_arm64.cc
@@ -2052,7 +2052,8 @@
Location index = locations->InAt(1);
Location out = locations->Out();
uint32_t offset = CodeGenerator::GetArrayDataOffset(instruction);
-
+ const bool maybe_compressed_char_at = mirror::kUseStringCompression &&
+ instruction->IsStringCharAt();
MacroAssembler* masm = GetVIXLAssembler();
UseScratchRegisterScope temps(masm);
// Block pools between `Load` and `MaybeRecordImplicitNullCheck`.
@@ -2070,9 +2071,28 @@
} else {
// General case.
MemOperand source = HeapOperand(obj);
+ Register length;
+ if (maybe_compressed_char_at) {
+ uint32_t count_offset = mirror::String::CountOffset().Uint32Value();
+ length = temps.AcquireW();
+ __ Ldr(length, HeapOperand(obj, count_offset));
+ codegen_->MaybeRecordImplicitNullCheck(instruction);
+ }
if (index.IsConstant()) {
- offset += Int64ConstantFrom(index) << Primitive::ComponentSizeShift(type);
- source = HeapOperand(obj, offset);
+ if (maybe_compressed_char_at) {
+ vixl::aarch64::Label uncompressed_load, done;
+ __ Tbz(length.W(), kWRegSize - 1, &uncompressed_load);
+ __ Ldrb(Register(OutputCPURegister(instruction)),
+ HeapOperand(obj, offset + Int64ConstantFrom(index)));
+ __ B(&done);
+ __ Bind(&uncompressed_load);
+ __ Ldrh(Register(OutputCPURegister(instruction)),
+ HeapOperand(obj, offset + (Int64ConstantFrom(index) << 1)));
+ __ Bind(&done);
+ } else {
+ offset += Int64ConstantFrom(index) << Primitive::ComponentSizeShift(type);
+ source = HeapOperand(obj, offset);
+ }
} else {
Register temp = temps.AcquireSameSizeAs(obj);
if (instruction->GetArray()->IsIntermediateAddress()) {
@@ -2090,11 +2110,24 @@
} else {
__ Add(temp, obj, offset);
}
- source = HeapOperand(temp, XRegisterFrom(index), LSL, Primitive::ComponentSizeShift(type));
+ if (maybe_compressed_char_at) {
+ vixl::aarch64::Label uncompressed_load, done;
+ __ Tbz(length.W(), kWRegSize - 1, &uncompressed_load);
+ __ Ldrb(Register(OutputCPURegister(instruction)),
+ HeapOperand(temp, XRegisterFrom(index), LSL, 0));
+ __ B(&done);
+ __ Bind(&uncompressed_load);
+ __ Ldrh(Register(OutputCPURegister(instruction)),
+ HeapOperand(temp, XRegisterFrom(index), LSL, 1));
+ __ Bind(&done);
+ } else {
+ source = HeapOperand(temp, XRegisterFrom(index), LSL, Primitive::ComponentSizeShift(type));
+ }
}
-
- codegen_->Load(type, OutputCPURegister(instruction), source);
- codegen_->MaybeRecordImplicitNullCheck(instruction);
+ if (!maybe_compressed_char_at) {
+ codegen_->Load(type, OutputCPURegister(instruction), source);
+ codegen_->MaybeRecordImplicitNullCheck(instruction);
+ }
if (type == Primitive::kPrimNot) {
static_assert(
@@ -2118,9 +2151,14 @@
void InstructionCodeGeneratorARM64::VisitArrayLength(HArrayLength* instruction) {
uint32_t offset = CodeGenerator::GetArrayLengthOffset(instruction);
+ vixl::aarch64::Register out = OutputRegister(instruction);
BlockPoolsScope block_pools(GetVIXLAssembler());
- __ Ldr(OutputRegister(instruction), HeapOperand(InputRegisterAt(instruction, 0), offset));
+ __ Ldr(out, HeapOperand(InputRegisterAt(instruction, 0), offset));
codegen_->MaybeRecordImplicitNullCheck(instruction);
+ // Mask out compression flag from String's array length.
+ if (mirror::kUseStringCompression && instruction->IsStringLength()) {
+ __ And(out.W(), out.W(), Operand(static_cast<int32_t>(INT32_MAX)));
+ }
}
void LocationsBuilderARM64::VisitArraySet(HArraySet* instruction) {
@@ -2312,7 +2350,6 @@
BoundsCheckSlowPathARM64* slow_path =
new (GetGraph()->GetArena()) BoundsCheckSlowPathARM64(instruction);
codegen_->AddSlowPath(slow_path);
-
__ Cmp(InputRegisterAt(instruction, 0), InputOperandAt(instruction, 1));
__ B(slow_path->GetEntryLabel(), hs);
}
diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc
index c300080..a7051ae 100644
--- a/compiler/optimizing/code_generator_x86.cc
+++ b/compiler/optimizing/code_generator_x86.cc
@@ -150,6 +150,9 @@
length_loc = Location::RegisterLocation(calling_convention.GetRegisterAt(2));
}
__ movl(length_loc.AsRegister<Register>(), array_len);
+ if (mirror::kUseStringCompression) {
+ __ andl(length_loc.AsRegister<Register>(), Immediate(INT32_MAX));
+ }
}
x86_codegen->EmitParallelMoves(
locations->InAt(0),
@@ -5021,7 +5024,23 @@
case Primitive::kPrimChar: {
Register out = out_loc.AsRegister<Register>();
- __ movzxw(out, CodeGeneratorX86::ArrayAddress(obj, index, TIMES_2, data_offset));
+ if (mirror::kUseStringCompression && instruction->IsStringCharAt()) {
+ // Branch cases into compressed and uncompressed for each index's type.
+ uint32_t count_offset = mirror::String::CountOffset().Uint32Value();
+ NearLabel done, not_compressed;
+ __ cmpl(Address(obj, count_offset), Immediate(0));
+ codegen_->MaybeRecordImplicitNullCheck(instruction);
+ __ j(kGreaterEqual, ¬_compressed);
+ __ movzxb(out, CodeGeneratorX86::ArrayAddress(obj, index, TIMES_1, data_offset));
+ __ jmp(&done);
+ __ Bind(¬_compressed);
+ __ movzxw(out, CodeGeneratorX86::ArrayAddress(obj, index, TIMES_2, data_offset));
+ __ Bind(&done);
+ } else {
+ // Common case for charAt of array of char or when string compression's
+ // feature is turned off.
+ __ movzxw(out, CodeGeneratorX86::ArrayAddress(obj, index, TIMES_2, data_offset));
+ }
break;
}
@@ -5359,6 +5378,10 @@
Register out = locations->Out().AsRegister<Register>();
__ movl(out, Address(obj, offset));
codegen_->MaybeRecordImplicitNullCheck(instruction);
+ // Mask out most significant bit in case the array is String's array of char.
+ if (mirror::kUseStringCompression && instruction->IsStringLength()) {
+ __ andl(out, Immediate(INT32_MAX));
+ }
}
void LocationsBuilderX86::VisitBoundsCheck(HBoundsCheck* instruction) {
@@ -5372,9 +5395,15 @@
if (!length->IsEmittedAtUseSite()) {
locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
}
+ // Need register to see array's length.
+ if (mirror::kUseStringCompression && instruction->IsStringCharAt()) {
+ locations->AddTemp(Location::RequiresRegister());
+ }
}
void InstructionCodeGeneratorX86::VisitBoundsCheck(HBoundsCheck* instruction) {
+ const bool is_string_compressed_char_at =
+ mirror::kUseStringCompression && instruction->IsStringCharAt();
LocationSummary* locations = instruction->GetLocations();
Location index_loc = locations->InAt(0);
Location length_loc = locations->InAt(1);
@@ -5409,13 +5438,23 @@
uint32_t len_offset = CodeGenerator::GetArrayLengthOffset(array_length->AsArrayLength());
Location array_loc = array_length->GetLocations()->InAt(0);
Address array_len(array_loc.AsRegister<Register>(), len_offset);
- if (index_loc.IsConstant()) {
- int32_t value = CodeGenerator::GetInt32ValueOf(index_loc.GetConstant());
- __ cmpl(array_len, Immediate(value));
+ if (is_string_compressed_char_at) {
+ Register length_reg = locations->GetTemp(0).AsRegister<Register>();
+ __ movl(length_reg, array_len);
+ codegen_->MaybeRecordImplicitNullCheck(array_length);
+ __ andl(length_reg, Immediate(INT32_MAX));
+ codegen_->GenerateIntCompare(length_reg, index_loc);
} else {
- __ cmpl(array_len, index_loc.AsRegister<Register>());
+ // Checking bounds for general case:
+ // Array of char or string's array with feature compression off.
+ if (index_loc.IsConstant()) {
+ int32_t value = CodeGenerator::GetInt32ValueOf(index_loc.GetConstant());
+ __ cmpl(array_len, Immediate(value));
+ } else {
+ __ cmpl(array_len, index_loc.AsRegister<Register>());
+ }
+ codegen_->MaybeRecordImplicitNullCheck(array_length);
}
- codegen_->MaybeRecordImplicitNullCheck(array_length);
} else {
codegen_->GenerateIntCompare(length_loc, index_loc);
}
@@ -7278,13 +7317,17 @@
void CodeGeneratorX86::GenerateIntCompare(Location lhs, Location rhs) {
Register lhs_reg = lhs.AsRegister<Register>();
+ GenerateIntCompare(lhs_reg, rhs);
+}
+
+void CodeGeneratorX86::GenerateIntCompare(Register lhs, Location rhs) {
if (rhs.IsConstant()) {
int32_t value = CodeGenerator::GetInt32ValueOf(rhs.GetConstant());
- Compare32BitValue(lhs_reg, value);
+ Compare32BitValue(lhs, value);
} else if (rhs.IsStackSlot()) {
- __ cmpl(lhs_reg, Address(ESP, rhs.GetStackIndex()));
+ __ cmpl(lhs, Address(ESP, rhs.GetStackIndex()));
} else {
- __ cmpl(lhs_reg, rhs.AsRegister<Register>());
+ __ cmpl(lhs, rhs.AsRegister<Register>());
}
}
diff --git a/compiler/optimizing/code_generator_x86.h b/compiler/optimizing/code_generator_x86.h
index 1ae9af3..1bd28da 100644
--- a/compiler/optimizing/code_generator_x86.h
+++ b/compiler/optimizing/code_generator_x86.h
@@ -474,6 +474,7 @@
// Compare int values. Supports only register locations for `lhs`.
void GenerateIntCompare(Location lhs, Location rhs);
+ void GenerateIntCompare(Register lhs, Location rhs);
// Construct address for array access.
static Address ArrayAddress(Register obj,
diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc
index f9a3e42..b243ee0 100644
--- a/compiler/optimizing/code_generator_x86_64.cc
+++ b/compiler/optimizing/code_generator_x86_64.cc
@@ -198,6 +198,9 @@
length_loc = Location::RegisterLocation(calling_convention.GetRegisterAt(2));
}
__ movl(length_loc.AsRegister<CpuRegister>(), array_len);
+ if (mirror::kUseStringCompression) {
+ __ andl(length_loc.AsRegister<CpuRegister>(), Immediate(INT32_MAX));
+ }
}
// We're moving two locations to locations that could overlap, so we need a parallel
@@ -4485,7 +4488,21 @@
case Primitive::kPrimChar: {
CpuRegister out = out_loc.AsRegister<CpuRegister>();
- __ movzxw(out, CodeGeneratorX86_64::ArrayAddress(obj, index, TIMES_2, data_offset));
+ if (mirror::kUseStringCompression && instruction->IsStringCharAt()) {
+ // Branch cases into compressed and uncompressed for each index's type.
+ uint32_t count_offset = mirror::String::CountOffset().Uint32Value();
+ NearLabel done, not_compressed;
+ __ cmpl(Address(obj, count_offset), Immediate(0));
+ codegen_->MaybeRecordImplicitNullCheck(instruction);
+ __ j(kGreaterEqual, ¬_compressed);
+ __ movzxb(out, CodeGeneratorX86_64::ArrayAddress(obj, index, TIMES_1, data_offset));
+ __ jmp(&done);
+ __ Bind(¬_compressed);
+ __ movzxw(out, CodeGeneratorX86_64::ArrayAddress(obj, index, TIMES_2, data_offset));
+ __ Bind(&done);
+ } else {
+ __ movzxw(out, CodeGeneratorX86_64::ArrayAddress(obj, index, TIMES_2, data_offset));
+ }
break;
}
@@ -4807,6 +4824,10 @@
CpuRegister out = locations->Out().AsRegister<CpuRegister>();
__ movl(out, Address(obj, offset));
codegen_->MaybeRecordImplicitNullCheck(instruction);
+ // Mask out most significant bit in case the array is String's array of char.
+ if (mirror::kUseStringCompression && instruction->IsStringLength()) {
+ __ andl(out, Immediate(INT32_MAX));
+ }
}
void LocationsBuilderX86_64::VisitBoundsCheck(HBoundsCheck* instruction) {
@@ -4856,13 +4877,23 @@
uint32_t len_offset = CodeGenerator::GetArrayLengthOffset(array_length->AsArrayLength());
Location array_loc = array_length->GetLocations()->InAt(0);
Address array_len(array_loc.AsRegister<CpuRegister>(), len_offset);
- if (index_loc.IsConstant()) {
- int32_t value = CodeGenerator::GetInt32ValueOf(index_loc.GetConstant());
- __ cmpl(array_len, Immediate(value));
+ if (mirror::kUseStringCompression && instruction->IsStringCharAt()) {
+ CpuRegister length_reg = CpuRegister(TMP);
+ __ movl(length_reg, array_len);
+ codegen_->MaybeRecordImplicitNullCheck(array_length);
+ __ andl(length_reg, Immediate(INT32_MAX));
+ codegen_->GenerateIntCompare(length_reg, index_loc);
} else {
- __ cmpl(array_len, index_loc.AsRegister<CpuRegister>());
+ // Checking the bound for general case:
+ // Array of char or String's array when the compression feature off.
+ if (index_loc.IsConstant()) {
+ int32_t value = CodeGenerator::GetInt32ValueOf(index_loc.GetConstant());
+ __ cmpl(array_len, Immediate(value));
+ } else {
+ __ cmpl(array_len, index_loc.AsRegister<CpuRegister>());
+ }
+ codegen_->MaybeRecordImplicitNullCheck(array_length);
}
- codegen_->MaybeRecordImplicitNullCheck(array_length);
} else {
codegen_->GenerateIntCompare(length_loc, index_loc);
}
@@ -6525,13 +6556,17 @@
void CodeGeneratorX86_64::GenerateIntCompare(Location lhs, Location rhs) {
CpuRegister lhs_reg = lhs.AsRegister<CpuRegister>();
+ GenerateIntCompare(lhs_reg, rhs);
+}
+
+void CodeGeneratorX86_64::GenerateIntCompare(CpuRegister lhs, Location rhs) {
if (rhs.IsConstant()) {
int32_t value = CodeGenerator::GetInt32ValueOf(rhs.GetConstant());
- Compare32BitValue(lhs_reg, value);
+ Compare32BitValue(lhs, value);
} else if (rhs.IsStackSlot()) {
- __ cmpl(lhs_reg, Address(CpuRegister(RSP), rhs.GetStackIndex()));
+ __ cmpl(lhs, Address(CpuRegister(RSP), rhs.GetStackIndex()));
} else {
- __ cmpl(lhs_reg, rhs.AsRegister<CpuRegister>());
+ __ cmpl(lhs, rhs.AsRegister<CpuRegister>());
}
}
diff --git a/compiler/optimizing/code_generator_x86_64.h b/compiler/optimizing/code_generator_x86_64.h
index 594f051..8dec44e 100644
--- a/compiler/optimizing/code_generator_x86_64.h
+++ b/compiler/optimizing/code_generator_x86_64.h
@@ -510,8 +510,9 @@
void Compare32BitValue(CpuRegister dest, int32_t value);
void Compare64BitValue(CpuRegister dest, int64_t value);
- // Compare int values. Supports only register locations for `lhs`.
+ // Compare int values. Supports register locations for `lhs`.
void GenerateIntCompare(Location lhs, Location rhs);
+ void GenerateIntCompare(CpuRegister lhs, Location rhs);
// Compare long values. Supports only register locations for `lhs`.
void GenerateLongCompare(Location lhs, Location rhs);
diff --git a/compiler/optimizing/inliner.cc b/compiler/optimizing/inliner.cc
index f21dc0e..af2fe9c 100644
--- a/compiler/optimizing/inliner.cc
+++ b/compiler/optimizing/inliner.cc
@@ -41,7 +41,7 @@
#include "sharpening.h"
#include "ssa_builder.h"
#include "ssa_phi_elimination.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
#include "thread.h"
namespace art {
@@ -1321,7 +1321,7 @@
HConstantFolding fold(callee_graph);
HSharpening sharpening(callee_graph, codegen_, dex_compilation_unit, compiler_driver_);
InstructionSimplifier simplify(callee_graph, stats_);
- IntrinsicsRecognizer intrinsics(callee_graph, compiler_driver_, stats_);
+ IntrinsicsRecognizer intrinsics(callee_graph, stats_);
HOptimization* optimizations[] = {
&intrinsics,
diff --git a/compiler/optimizing/instruction_builder.cc b/compiler/optimizing/instruction_builder.cc
index 3b08d9f..f7d67db 100644
--- a/compiler/optimizing/instruction_builder.cc
+++ b/compiler/optimizing/instruction_builder.cc
@@ -22,7 +22,7 @@
#include "dex_instruction-inl.h"
#include "driver/compiler_options.h"
#include "imtable-inl.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
namespace art {
@@ -675,7 +675,7 @@
ClassLinker* class_linker = dex_compilation_unit_->GetClassLinker();
Handle<mirror::ClassLoader> class_loader(hs.NewHandle(
- soa.Decode<mirror::ClassLoader*>(dex_compilation_unit_->GetClassLoader())));
+ soa.Decode<mirror::ClassLoader>(dex_compilation_unit_->GetClassLoader())));
Handle<mirror::Class> compiling_class(hs.NewHandle(GetCompilingClass()));
// We fetch the referenced class eagerly (that is, the class pointed by in the MethodId
// at method_idx), as `CanAccessResolvedMethod` expects it be be in the dex cache.
@@ -1284,7 +1284,7 @@
ScopedObjectAccess soa(Thread::Current());
StackHandleScope<1> hs(soa.Self());
Handle<mirror::ClassLoader> class_loader(hs.NewHandle(
- soa.Decode<mirror::ClassLoader*>(compilation_unit.GetClassLoader())));
+ soa.Decode<mirror::ClassLoader>(compilation_unit.GetClassLoader())));
Handle<mirror::DexCache> dex_cache = compilation_unit.GetDexCache();
return driver->ResolveCompilingMethodsClass(soa, dex_cache, class_loader, &compilation_unit);
@@ -1303,7 +1303,7 @@
StackHandleScope<3> hs(soa.Self());
Handle<mirror::DexCache> dex_cache = dex_compilation_unit_->GetDexCache();
Handle<mirror::ClassLoader> class_loader(hs.NewHandle(
- soa.Decode<mirror::ClassLoader*>(dex_compilation_unit_->GetClassLoader())));
+ soa.Decode<mirror::ClassLoader>(dex_compilation_unit_->GetClassLoader())));
Handle<mirror::Class> cls(hs.NewHandle(compiler_driver_->ResolveClass(
soa, dex_cache, class_loader, type_index, dex_compilation_unit_)));
Handle<mirror::Class> outer_class(hs.NewHandle(GetOutermostCompilingClass()));
@@ -1344,7 +1344,7 @@
StackHandleScope<3> hs(soa.Self());
Handle<mirror::DexCache> dex_cache = dex_compilation_unit_->GetDexCache();
Handle<mirror::ClassLoader> class_loader(hs.NewHandle(
- soa.Decode<mirror::ClassLoader*>(dex_compilation_unit_->GetClassLoader())));
+ soa.Decode<mirror::ClassLoader>(dex_compilation_unit_->GetClassLoader())));
ArtField* resolved_field = compiler_driver_->ResolveField(
soa, dex_cache, class_loader, dex_compilation_unit_, field_index, true);
diff --git a/compiler/optimizing/instruction_simplifier.cc b/compiler/optimizing/instruction_simplifier.cc
index ff829af..3bb1c1d 100644
--- a/compiler/optimizing/instruction_simplifier.cc
+++ b/compiler/optimizing/instruction_simplifier.cc
@@ -18,7 +18,7 @@
#include "intrinsics.h"
#include "mirror/class-inl.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
namespace art {
diff --git a/compiler/optimizing/instruction_simplifier_arm.cc b/compiler/optimizing/instruction_simplifier_arm.cc
index 495f3fd..56e4c7a 100644
--- a/compiler/optimizing/instruction_simplifier_arm.cc
+++ b/compiler/optimizing/instruction_simplifier_arm.cc
@@ -44,6 +44,14 @@
size_t data_offset = CodeGenerator::GetArrayDataOffset(instruction);
Primitive::Type type = instruction->GetType();
+ // TODO: Implement reading (length + compression) for String compression feature from
+ // negative offset (count_offset - data_offset). Thumb2Assembler does not support T4
+ // encoding of "LDR (immediate)" at the moment.
+ // Don't move array pointer if it is charAt because we need to take the count first.
+ if (mirror::kUseStringCompression && instruction->IsStringCharAt()) {
+ return;
+ }
+
if (type == Primitive::kPrimLong
|| type == Primitive::kPrimFloat
|| type == Primitive::kPrimDouble) {
diff --git a/compiler/optimizing/instruction_simplifier_arm64.cc b/compiler/optimizing/instruction_simplifier_arm64.cc
index 6d107d5..d0dd650 100644
--- a/compiler/optimizing/instruction_simplifier_arm64.cc
+++ b/compiler/optimizing/instruction_simplifier_arm64.cc
@@ -140,6 +140,13 @@
void InstructionSimplifierArm64Visitor::VisitArrayGet(HArrayGet* instruction) {
size_t data_offset = CodeGenerator::GetArrayDataOffset(instruction);
+ // Don't move the array pointer if it is charAt because we need to take the count first.
+ // TODO: Implement reading (length + compression) for String compression feature from
+ // negative offset (count_offset - data_offset) using LDP and clobbering an extra temporary.
+ // Note that "LDR (Immediate)" does not have a "signed offset" encoding.
+ if (mirror::kUseStringCompression && instruction->IsStringCharAt()) {
+ return;
+ }
if (TryExtractArrayAccessAddress(instruction,
instruction->GetArray(),
instruction->GetIndex(),
diff --git a/compiler/optimizing/intrinsics.cc b/compiler/optimizing/intrinsics.cc
index 4d4bbcf..412ccfc 100644
--- a/compiler/optimizing/intrinsics.cc
+++ b/compiler/optimizing/intrinsics.cc
@@ -18,14 +18,11 @@
#include "art_method.h"
#include "class_linker.h"
-#include "dex/quick/dex_file_method_inliner.h"
-#include "dex/quick/dex_file_to_method_inliner_map.h"
#include "driver/compiler_driver.h"
#include "invoke_type.h"
#include "mirror/dex_cache-inl.h"
#include "nodes.h"
-#include "quick/inline_method_analyser.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
#include "thread-inl.h"
#include "utils.h"
@@ -36,7 +33,7 @@
switch (i) {
case Intrinsics::kNone:
return kInterface; // Non-sensical for intrinsic.
-#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache, SideEffects, Exceptions) \
+#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache, SideEffects, Exceptions, ...) \
case Intrinsics::k ## Name: \
return IsStatic;
#include "intrinsics_list.h"
@@ -52,7 +49,7 @@
switch (i) {
case Intrinsics::kNone:
return kNeedsEnvironmentOrCache; // Non-sensical for intrinsic.
-#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache, SideEffects, Exceptions) \
+#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache, SideEffects, Exceptions, ...) \
case Intrinsics::k ## Name: \
return NeedsEnvironmentOrCache;
#include "intrinsics_list.h"
@@ -68,7 +65,7 @@
switch (i) {
case Intrinsics::kNone:
return kAllSideEffects;
-#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache, SideEffects, Exceptions) \
+#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache, SideEffects, Exceptions, ...) \
case Intrinsics::k ## Name: \
return SideEffects;
#include "intrinsics_list.h"
@@ -84,7 +81,7 @@
switch (i) {
case Intrinsics::kNone:
return kCanThrow;
-#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache, SideEffects, Exceptions) \
+#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache, SideEffects, Exceptions, ...) \
case Intrinsics::k ## Name: \
return Exceptions;
#include "intrinsics_list.h"
@@ -95,430 +92,7 @@
return kCanThrow;
}
-static Primitive::Type GetType(uint64_t data, bool is_op_size) {
- if (is_op_size) {
- switch (static_cast<OpSize>(data)) {
- case kSignedByte:
- return Primitive::kPrimByte;
- case kSignedHalf:
- return Primitive::kPrimShort;
- case k32:
- return Primitive::kPrimInt;
- case k64:
- return Primitive::kPrimLong;
- default:
- LOG(FATAL) << "Unknown/unsupported op size " << data;
- UNREACHABLE();
- }
- } else {
- if ((data & kIntrinsicFlagIsLong) != 0) {
- return Primitive::kPrimLong;
- }
- if ((data & kIntrinsicFlagIsObject) != 0) {
- return Primitive::kPrimNot;
- }
- return Primitive::kPrimInt;
- }
-}
-
-static Intrinsics GetIntrinsic(InlineMethod method) {
- switch (method.opcode) {
- // Floating-point conversions.
- case kIntrinsicDoubleCvt:
- return ((method.d.data & kIntrinsicFlagToFloatingPoint) == 0) ?
- Intrinsics::kDoubleDoubleToRawLongBits : Intrinsics::kDoubleLongBitsToDouble;
- case kIntrinsicFloatCvt:
- return ((method.d.data & kIntrinsicFlagToFloatingPoint) == 0) ?
- Intrinsics::kFloatFloatToRawIntBits : Intrinsics::kFloatIntBitsToFloat;
- case kIntrinsicFloat2Int:
- return Intrinsics::kFloatFloatToIntBits;
- case kIntrinsicDouble2Long:
- return Intrinsics::kDoubleDoubleToLongBits;
-
- // Floating-point tests.
- case kIntrinsicFloatIsInfinite:
- return Intrinsics::kFloatIsInfinite;
- case kIntrinsicDoubleIsInfinite:
- return Intrinsics::kDoubleIsInfinite;
- case kIntrinsicFloatIsNaN:
- return Intrinsics::kFloatIsNaN;
- case kIntrinsicDoubleIsNaN:
- return Intrinsics::kDoubleIsNaN;
-
- // Bit manipulations.
- case kIntrinsicReverseBits:
- switch (GetType(method.d.data, true)) {
- case Primitive::kPrimInt:
- return Intrinsics::kIntegerReverse;
- case Primitive::kPrimLong:
- return Intrinsics::kLongReverse;
- default:
- LOG(FATAL) << "Unknown/unsupported op size " << method.d.data;
- UNREACHABLE();
- }
- case kIntrinsicReverseBytes:
- switch (GetType(method.d.data, true)) {
- case Primitive::kPrimShort:
- return Intrinsics::kShortReverseBytes;
- case Primitive::kPrimInt:
- return Intrinsics::kIntegerReverseBytes;
- case Primitive::kPrimLong:
- return Intrinsics::kLongReverseBytes;
- default:
- LOG(FATAL) << "Unknown/unsupported op size " << method.d.data;
- UNREACHABLE();
- }
- case kIntrinsicRotateRight:
- switch (GetType(method.d.data, true)) {
- case Primitive::kPrimInt:
- return Intrinsics::kIntegerRotateRight;
- case Primitive::kPrimLong:
- return Intrinsics::kLongRotateRight;
- default:
- LOG(FATAL) << "Unknown/unsupported op size " << method.d.data;
- UNREACHABLE();
- }
- case kIntrinsicRotateLeft:
- switch (GetType(method.d.data, true)) {
- case Primitive::kPrimInt:
- return Intrinsics::kIntegerRotateLeft;
- case Primitive::kPrimLong:
- return Intrinsics::kLongRotateLeft;
- default:
- LOG(FATAL) << "Unknown/unsupported op size " << method.d.data;
- UNREACHABLE();
- }
-
- // Misc data processing.
- case kIntrinsicBitCount:
- switch (GetType(method.d.data, true)) {
- case Primitive::kPrimInt:
- return Intrinsics::kIntegerBitCount;
- case Primitive::kPrimLong:
- return Intrinsics::kLongBitCount;
- default:
- LOG(FATAL) << "Unknown/unsupported op size " << method.d.data;
- UNREACHABLE();
- }
- case kIntrinsicCompare:
- switch (GetType(method.d.data, true)) {
- case Primitive::kPrimInt:
- return Intrinsics::kIntegerCompare;
- case Primitive::kPrimLong:
- return Intrinsics::kLongCompare;
- default:
- LOG(FATAL) << "Unknown/unsupported op size " << method.d.data;
- UNREACHABLE();
- }
- case kIntrinsicHighestOneBit:
- switch (GetType(method.d.data, true)) {
- case Primitive::kPrimInt:
- return Intrinsics::kIntegerHighestOneBit;
- case Primitive::kPrimLong:
- return Intrinsics::kLongHighestOneBit;
- default:
- LOG(FATAL) << "Unknown/unsupported op size " << method.d.data;
- UNREACHABLE();
- }
- case kIntrinsicLowestOneBit:
- switch (GetType(method.d.data, true)) {
- case Primitive::kPrimInt:
- return Intrinsics::kIntegerLowestOneBit;
- case Primitive::kPrimLong:
- return Intrinsics::kLongLowestOneBit;
- default:
- LOG(FATAL) << "Unknown/unsupported op size " << method.d.data;
- UNREACHABLE();
- }
- case kIntrinsicNumberOfLeadingZeros:
- switch (GetType(method.d.data, true)) {
- case Primitive::kPrimInt:
- return Intrinsics::kIntegerNumberOfLeadingZeros;
- case Primitive::kPrimLong:
- return Intrinsics::kLongNumberOfLeadingZeros;
- default:
- LOG(FATAL) << "Unknown/unsupported op size " << method.d.data;
- UNREACHABLE();
- }
- case kIntrinsicNumberOfTrailingZeros:
- switch (GetType(method.d.data, true)) {
- case Primitive::kPrimInt:
- return Intrinsics::kIntegerNumberOfTrailingZeros;
- case Primitive::kPrimLong:
- return Intrinsics::kLongNumberOfTrailingZeros;
- default:
- LOG(FATAL) << "Unknown/unsupported op size " << method.d.data;
- UNREACHABLE();
- }
- case kIntrinsicSignum:
- switch (GetType(method.d.data, true)) {
- case Primitive::kPrimInt:
- return Intrinsics::kIntegerSignum;
- case Primitive::kPrimLong:
- return Intrinsics::kLongSignum;
- default:
- LOG(FATAL) << "Unknown/unsupported op size " << method.d.data;
- UNREACHABLE();
- }
-
- // Abs.
- case kIntrinsicAbsDouble:
- return Intrinsics::kMathAbsDouble;
- case kIntrinsicAbsFloat:
- return Intrinsics::kMathAbsFloat;
- case kIntrinsicAbsInt:
- return Intrinsics::kMathAbsInt;
- case kIntrinsicAbsLong:
- return Intrinsics::kMathAbsLong;
-
- // Min/max.
- case kIntrinsicMinMaxDouble:
- return ((method.d.data & kIntrinsicFlagMin) == 0) ?
- Intrinsics::kMathMaxDoubleDouble : Intrinsics::kMathMinDoubleDouble;
- case kIntrinsicMinMaxFloat:
- return ((method.d.data & kIntrinsicFlagMin) == 0) ?
- Intrinsics::kMathMaxFloatFloat : Intrinsics::kMathMinFloatFloat;
- case kIntrinsicMinMaxInt:
- return ((method.d.data & kIntrinsicFlagMin) == 0) ?
- Intrinsics::kMathMaxIntInt : Intrinsics::kMathMinIntInt;
- case kIntrinsicMinMaxLong:
- return ((method.d.data & kIntrinsicFlagMin) == 0) ?
- Intrinsics::kMathMaxLongLong : Intrinsics::kMathMinLongLong;
-
- // More math builtins.
- case kIntrinsicCos:
- return Intrinsics::kMathCos;
- case kIntrinsicSin:
- return Intrinsics::kMathSin;
- case kIntrinsicAcos:
- return Intrinsics::kMathAcos;
- case kIntrinsicAsin:
- return Intrinsics::kMathAsin;
- case kIntrinsicAtan:
- return Intrinsics::kMathAtan;
- case kIntrinsicAtan2:
- return Intrinsics::kMathAtan2;
- case kIntrinsicCbrt:
- return Intrinsics::kMathCbrt;
- case kIntrinsicCosh:
- return Intrinsics::kMathCosh;
- case kIntrinsicExp:
- return Intrinsics::kMathExp;
- case kIntrinsicExpm1:
- return Intrinsics::kMathExpm1;
- case kIntrinsicHypot:
- return Intrinsics::kMathHypot;
- case kIntrinsicLog:
- return Intrinsics::kMathLog;
- case kIntrinsicLog10:
- return Intrinsics::kMathLog10;
- case kIntrinsicNextAfter:
- return Intrinsics::kMathNextAfter;
- case kIntrinsicSinh:
- return Intrinsics::kMathSinh;
- case kIntrinsicTan:
- return Intrinsics::kMathTan;
- case kIntrinsicTanh:
- return Intrinsics::kMathTanh;
-
- // Misc math.
- case kIntrinsicSqrt:
- return Intrinsics::kMathSqrt;
- case kIntrinsicCeil:
- return Intrinsics::kMathCeil;
- case kIntrinsicFloor:
- return Intrinsics::kMathFloor;
- case kIntrinsicRint:
- return Intrinsics::kMathRint;
- case kIntrinsicRoundDouble:
- return Intrinsics::kMathRoundDouble;
- case kIntrinsicRoundFloat:
- return Intrinsics::kMathRoundFloat;
-
- // System.arraycopy.
- case kIntrinsicSystemArrayCopyCharArray:
- return Intrinsics::kSystemArrayCopyChar;
-
- case kIntrinsicSystemArrayCopy:
- return Intrinsics::kSystemArrayCopy;
-
- // Thread.currentThread.
- case kIntrinsicCurrentThread:
- return Intrinsics::kThreadCurrentThread;
-
- // Memory.peek.
- case kIntrinsicPeek:
- switch (GetType(method.d.data, true)) {
- case Primitive::kPrimByte:
- return Intrinsics::kMemoryPeekByte;
- case Primitive::kPrimShort:
- return Intrinsics::kMemoryPeekShortNative;
- case Primitive::kPrimInt:
- return Intrinsics::kMemoryPeekIntNative;
- case Primitive::kPrimLong:
- return Intrinsics::kMemoryPeekLongNative;
- default:
- LOG(FATAL) << "Unknown/unsupported op size " << method.d.data;
- UNREACHABLE();
- }
-
- // Memory.poke.
- case kIntrinsicPoke:
- switch (GetType(method.d.data, true)) {
- case Primitive::kPrimByte:
- return Intrinsics::kMemoryPokeByte;
- case Primitive::kPrimShort:
- return Intrinsics::kMemoryPokeShortNative;
- case Primitive::kPrimInt:
- return Intrinsics::kMemoryPokeIntNative;
- case Primitive::kPrimLong:
- return Intrinsics::kMemoryPokeLongNative;
- default:
- LOG(FATAL) << "Unknown/unsupported op size " << method.d.data;
- UNREACHABLE();
- }
-
- // String.
- case kIntrinsicCharAt:
- return Intrinsics::kStringCharAt;
- case kIntrinsicCompareTo:
- return Intrinsics::kStringCompareTo;
- case kIntrinsicEquals:
- return Intrinsics::kStringEquals;
- case kIntrinsicGetCharsNoCheck:
- return Intrinsics::kStringGetCharsNoCheck;
- case kIntrinsicIsEmptyOrLength:
- return ((method.d.data & kIntrinsicFlagIsEmpty) == 0) ?
- Intrinsics::kStringLength : Intrinsics::kStringIsEmpty;
- case kIntrinsicIndexOf:
- return ((method.d.data & kIntrinsicFlagBase0) == 0) ?
- Intrinsics::kStringIndexOfAfter : Intrinsics::kStringIndexOf;
- case kIntrinsicNewStringFromBytes:
- return Intrinsics::kStringNewStringFromBytes;
- case kIntrinsicNewStringFromChars:
- return Intrinsics::kStringNewStringFromChars;
- case kIntrinsicNewStringFromString:
- return Intrinsics::kStringNewStringFromString;
-
- case kIntrinsicCas:
- switch (GetType(method.d.data, false)) {
- case Primitive::kPrimNot:
- return Intrinsics::kUnsafeCASObject;
- case Primitive::kPrimInt:
- return Intrinsics::kUnsafeCASInt;
- case Primitive::kPrimLong:
- return Intrinsics::kUnsafeCASLong;
- default:
- LOG(FATAL) << "Unknown/unsupported op size " << method.d.data;
- UNREACHABLE();
- }
- case kIntrinsicUnsafeGet: {
- const bool is_volatile = (method.d.data & kIntrinsicFlagIsVolatile);
- switch (GetType(method.d.data, false)) {
- case Primitive::kPrimInt:
- return is_volatile ? Intrinsics::kUnsafeGetVolatile : Intrinsics::kUnsafeGet;
- case Primitive::kPrimLong:
- return is_volatile ? Intrinsics::kUnsafeGetLongVolatile : Intrinsics::kUnsafeGetLong;
- case Primitive::kPrimNot:
- return is_volatile ? Intrinsics::kUnsafeGetObjectVolatile : Intrinsics::kUnsafeGetObject;
- default:
- LOG(FATAL) << "Unknown/unsupported op size " << method.d.data;
- UNREACHABLE();
- }
- }
- case kIntrinsicUnsafePut: {
- enum Sync { kNoSync, kVolatile, kOrdered };
- const Sync sync =
- ((method.d.data & kIntrinsicFlagIsVolatile) != 0) ? kVolatile :
- ((method.d.data & kIntrinsicFlagIsOrdered) != 0) ? kOrdered :
- kNoSync;
- switch (GetType(method.d.data, false)) {
- case Primitive::kPrimInt:
- switch (sync) {
- case kNoSync:
- return Intrinsics::kUnsafePut;
- case kVolatile:
- return Intrinsics::kUnsafePutVolatile;
- case kOrdered:
- return Intrinsics::kUnsafePutOrdered;
- }
- break;
- case Primitive::kPrimLong:
- switch (sync) {
- case kNoSync:
- return Intrinsics::kUnsafePutLong;
- case kVolatile:
- return Intrinsics::kUnsafePutLongVolatile;
- case kOrdered:
- return Intrinsics::kUnsafePutLongOrdered;
- }
- break;
- case Primitive::kPrimNot:
- switch (sync) {
- case kNoSync:
- return Intrinsics::kUnsafePutObject;
- case kVolatile:
- return Intrinsics::kUnsafePutObjectVolatile;
- case kOrdered:
- return Intrinsics::kUnsafePutObjectOrdered;
- }
- break;
- default:
- LOG(FATAL) << "Unknown/unsupported op size " << method.d.data;
- UNREACHABLE();
- }
- break;
- }
-
- // 1.8.
- case kIntrinsicUnsafeGetAndAddInt:
- return Intrinsics::kUnsafeGetAndAddInt;
- case kIntrinsicUnsafeGetAndAddLong:
- return Intrinsics::kUnsafeGetAndAddLong;
- case kIntrinsicUnsafeGetAndSetInt:
- return Intrinsics::kUnsafeGetAndSetInt;
- case kIntrinsicUnsafeGetAndSetLong:
- return Intrinsics::kUnsafeGetAndSetLong;
- case kIntrinsicUnsafeGetAndSetObject:
- return Intrinsics::kUnsafeGetAndSetObject;
- case kIntrinsicUnsafeLoadFence:
- return Intrinsics::kUnsafeLoadFence;
- case kIntrinsicUnsafeStoreFence:
- return Intrinsics::kUnsafeStoreFence;
- case kIntrinsicUnsafeFullFence:
- return Intrinsics::kUnsafeFullFence;
-
- // Virtual cases.
-
- case kIntrinsicReferenceGetReferent:
- return Intrinsics::kReferenceGetReferent;
-
- // Quick inliner cases. Remove after refactoring. They are here so that we can use the
- // compiler to warn on missing cases.
-
- case kInlineOpNop:
- case kInlineOpReturnArg:
- case kInlineOpNonWideConst:
- case kInlineOpIGet:
- case kInlineOpIPut:
- case kInlineOpConstructor:
- return Intrinsics::kNone;
-
- // String init cases, not intrinsics.
-
- case kInlineStringInit:
- return Intrinsics::kNone;
-
- // No default case to make the compiler warn on missing cases.
- }
- return Intrinsics::kNone;
-}
-
-static bool CheckInvokeType(Intrinsics intrinsic, HInvoke* invoke, const DexFile& dex_file) {
- // The DexFileMethodInliner should have checked whether the methods are agreeing with
- // what we expect, i.e., static methods are called as such. Add another check here for
- // our expectations:
- //
+static bool CheckInvokeType(Intrinsics intrinsic, HInvoke* invoke) {
// Whenever the intrinsic is marked as static, report an error if we find an InvokeVirtual.
//
// Whenever the intrinsic is marked as direct and we find an InvokeVirtual, a devirtualization
@@ -542,13 +116,9 @@
return true;
}
if (invoke_type == kVirtual) {
- ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+ ArtMethod* art_method = invoke->GetResolvedMethod();
ScopedObjectAccess soa(Thread::Current());
- ArtMethod* art_method =
- class_linker->FindDexCache(soa.Self(), dex_file)->GetResolvedMethod(
- invoke->GetDexMethodIndex(), class_linker->GetImagePointerSize());
- return art_method != nullptr &&
- (art_method->IsFinal() || art_method->GetDeclaringClass()->IsFinal());
+ return (art_method->IsFinal() || art_method->GetDeclaringClass()->IsFinal());
}
return false;
@@ -561,8 +131,8 @@
}
}
-// TODO: Refactor DexFileMethodInliner and have something nicer than InlineMethod.
void IntrinsicsRecognizer::Run() {
+ ScopedObjectAccess soa(Thread::Current());
for (HReversePostOrderIterator it(*graph_); !it.Done(); it.Advance()) {
HBasicBlock* block = it.Current();
for (HInstructionIterator inst_it(block->GetInstructions()); !inst_it.Done();
@@ -570,26 +140,20 @@
HInstruction* inst = inst_it.Current();
if (inst->IsInvoke()) {
HInvoke* invoke = inst->AsInvoke();
- InlineMethod method;
- const DexFile& dex_file = invoke->GetDexFile();
- DexFileMethodInliner* inliner = driver_->GetMethodInlinerMap()->GetMethodInliner(&dex_file);
- DCHECK(inliner != nullptr);
- if (inliner->IsIntrinsic(invoke->GetDexMethodIndex(), &method)) {
- Intrinsics intrinsic = GetIntrinsic(method);
-
- if (intrinsic != Intrinsics::kNone) {
- if (!CheckInvokeType(intrinsic, invoke, dex_file)) {
- LOG(WARNING) << "Found an intrinsic with unexpected invoke type: "
- << intrinsic << " for "
- << PrettyMethod(invoke->GetDexMethodIndex(), invoke->GetDexFile())
- << invoke->DebugName();
- } else {
- invoke->SetIntrinsic(intrinsic,
- NeedsEnvironmentOrCache(intrinsic),
- GetSideEffects(intrinsic),
- GetExceptions(intrinsic));
- MaybeRecordStat(MethodCompilationStat::kIntrinsicRecognized);
- }
+ ArtMethod* art_method = invoke->GetResolvedMethod();
+ if (art_method != nullptr && art_method->IsIntrinsic()) {
+ Intrinsics intrinsic = static_cast<Intrinsics>(art_method->GetIntrinsic());
+ if (!CheckInvokeType(intrinsic, invoke)) {
+ LOG(WARNING) << "Found an intrinsic with unexpected invoke type: "
+ << intrinsic << " for "
+ << PrettyMethod(invoke->GetDexMethodIndex(), invoke->GetDexFile())
+ << invoke->DebugName();
+ } else {
+ invoke->SetIntrinsic(intrinsic,
+ NeedsEnvironmentOrCache(intrinsic),
+ GetSideEffects(intrinsic),
+ GetExceptions(intrinsic));
+ MaybeRecordStat(MethodCompilationStat::kIntrinsicRecognized);
}
}
}
@@ -602,7 +166,7 @@
case Intrinsics::kNone:
os << "None";
break;
-#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache, SideEffects, Exceptions) \
+#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache, SideEffects, Exceptions, ...) \
case Intrinsics::k ## Name: \
os << # Name; \
break;
diff --git a/compiler/optimizing/intrinsics.h b/compiler/optimizing/intrinsics.h
index 62f731d..1e73cf6 100644
--- a/compiler/optimizing/intrinsics.h
+++ b/compiler/optimizing/intrinsics.h
@@ -34,17 +34,14 @@
// Recognize intrinsics from HInvoke nodes.
class IntrinsicsRecognizer : public HOptimization {
public:
- IntrinsicsRecognizer(HGraph* graph, CompilerDriver* driver, OptimizingCompilerStats* stats)
- : HOptimization(graph, kIntrinsicsRecognizerPassName, stats),
- driver_(driver) {}
+ IntrinsicsRecognizer(HGraph* graph, OptimizingCompilerStats* stats)
+ : HOptimization(graph, kIntrinsicsRecognizerPassName, stats) {}
void Run() OVERRIDE;
static constexpr const char* kIntrinsicsRecognizerPassName = "intrinsics_recognition";
private:
- CompilerDriver* driver_;
-
DISALLOW_COPY_AND_ASSIGN(IntrinsicsRecognizer);
};
@@ -58,7 +55,7 @@
switch (invoke->GetIntrinsic()) {
case Intrinsics::kNone:
return;
-#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironment, SideEffects, Exceptions) \
+#define OPTIMIZING_INTRINSICS(Name, ...) \
case Intrinsics::k ## Name: \
Visit ## Name(invoke); \
return;
@@ -73,7 +70,7 @@
// Define visitor methods.
-#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironment, SideEffects, Exceptions) \
+#define OPTIMIZING_INTRINSICS(Name, ...) \
virtual void Visit ## Name(HInvoke* invoke ATTRIBUTE_UNUSED) { \
}
#include "intrinsics_list.h"
diff --git a/compiler/optimizing/intrinsics_arm.cc b/compiler/optimizing/intrinsics_arm.cc
index fd2da10..96a6ecb 100644
--- a/compiler/optimizing/intrinsics_arm.cc
+++ b/compiler/optimizing/intrinsics_arm.cc
@@ -1039,6 +1039,11 @@
locations->AddTemp(Location::RequiresRegister());
locations->AddTemp(Location::RequiresRegister());
locations->AddTemp(Location::RequiresRegister());
+ // Need temporary registers for String compression's feature.
+ if (mirror::kUseStringCompression) {
+ locations->AddTemp(Location::RequiresRegister());
+ locations->AddTemp(Location::RequiresRegister());
+ }
locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
}
@@ -1053,10 +1058,16 @@
Register temp0 = locations->GetTemp(0).AsRegister<Register>();
Register temp1 = locations->GetTemp(1).AsRegister<Register>();
Register temp2 = locations->GetTemp(2).AsRegister<Register>();
+ Register temp3, temp4;
+ if (mirror::kUseStringCompression) {
+ temp3 = locations->GetTemp(3).AsRegister<Register>();
+ temp4 = locations->GetTemp(4).AsRegister<Register>();
+ }
Label loop;
Label find_char_diff;
Label end;
+ Label different_compression;
// Get offsets of count and value fields within a string object.
const int32_t count_offset = mirror::String::CountOffset().Int32Value();
@@ -1077,20 +1088,40 @@
// Reference equality check, return 0 if same reference.
__ subs(out, str, ShifterOperand(arg));
__ b(&end, EQ);
- // Load lengths of this and argument strings.
- __ ldr(temp2, Address(str, count_offset));
- __ ldr(temp1, Address(arg, count_offset));
+ if (mirror::kUseStringCompression) {
+ // Load lengths of this and argument strings.
+ __ ldr(temp3, Address(str, count_offset));
+ __ ldr(temp4, Address(arg, count_offset));
+ // Clean out compression flag from lengths.
+ __ bic(temp0, temp3, ShifterOperand(0x80000000));
+ __ bic(IP, temp4, ShifterOperand(0x80000000));
+ } else {
+ // Load lengths of this and argument strings.
+ __ ldr(temp0, Address(str, count_offset));
+ __ ldr(IP, Address(arg, count_offset));
+ }
// out = length diff.
- __ subs(out, temp2, ShifterOperand(temp1));
+ __ subs(out, temp0, ShifterOperand(IP));
// temp0 = min(len(str), len(arg)).
- __ it(Condition::LT, kItElse);
- __ mov(temp0, ShifterOperand(temp2), Condition::LT);
- __ mov(temp0, ShifterOperand(temp1), Condition::GE);
+ __ it(GT);
+ __ mov(temp0, ShifterOperand(IP), GT);
// Shorter string is empty?
__ CompareAndBranchIfZero(temp0, &end);
+ if (mirror::kUseStringCompression) {
+ // Check if both strings using same compression style to use this comparison loop.
+ __ eors(temp3, temp3, ShifterOperand(temp4));
+ __ b(&different_compression, MI);
+ }
// Store offset of string value in preparation for comparison loop.
__ mov(temp1, ShifterOperand(value_offset));
+ if (mirror::kUseStringCompression) {
+ // For string compression, calculate the number of bytes to compare (not chars).
+ // This could in theory exceed INT32_MAX, so treat temp0 as unsigned.
+ __ cmp(temp4, ShifterOperand(0));
+ __ it(GE);
+ __ add(temp0, temp0, ShifterOperand(temp0), GE);
+ }
// Assertions that must hold in order to compare multiple characters at a time.
CHECK_ALIGNED(value_offset, 8);
@@ -1100,6 +1131,7 @@
const size_t char_size = Primitive::ComponentSize(Primitive::kPrimChar);
DCHECK_EQ(char_size, 2u);
+ Label find_char_diff_2nd_cmp;
// Unrolled loop comparing 4x16-bit chars per iteration (ok because of string data alignment).
__ Bind(&loop);
__ ldr(IP, Address(str, temp1));
@@ -1107,43 +1139,113 @@
__ cmp(IP, ShifterOperand(temp2));
__ b(&find_char_diff, NE);
__ add(temp1, temp1, ShifterOperand(char_size * 2));
- __ sub(temp0, temp0, ShifterOperand(2));
__ ldr(IP, Address(str, temp1));
__ ldr(temp2, Address(arg, temp1));
__ cmp(IP, ShifterOperand(temp2));
- __ b(&find_char_diff, NE);
+ __ b(&find_char_diff_2nd_cmp, NE);
__ add(temp1, temp1, ShifterOperand(char_size * 2));
- __ subs(temp0, temp0, ShifterOperand(2));
-
- __ b(&loop, GT);
+ // With string compression, we have compared 8 bytes, otherwise 4 chars.
+ __ subs(temp0, temp0, ShifterOperand(mirror::kUseStringCompression ? 8 : 4));
+ __ b(&loop, HI);
__ b(&end);
- // Find the single 16-bit character difference.
+ __ Bind(&find_char_diff_2nd_cmp);
+ if (mirror::kUseStringCompression) {
+ __ subs(temp0, temp0, ShifterOperand(4)); // 4 bytes previously compared.
+ __ b(&end, LS); // Was the second comparison fully beyond the end?
+ } else {
+ // Without string compression, we can start treating temp0 as signed
+ // and rely on the signed comparison below.
+ __ sub(temp0, temp0, ShifterOperand(2));
+ }
+
+ // Find the single character difference.
__ Bind(&find_char_diff);
// Get the bit position of the first character that differs.
__ eor(temp1, temp2, ShifterOperand(IP));
__ rbit(temp1, temp1);
__ clz(temp1, temp1);
- // temp0 = number of 16-bit characters remaining to compare.
- // (it could be < 1 if a difference is found after the first SUB in the comparison loop, and
- // after the end of the shorter string data).
+ // temp0 = number of characters remaining to compare.
+ // (Without string compression, it could be < 1 if a difference is found by the second CMP
+ // in the comparison loop, and after the end of the shorter string data).
- // (temp1 >> 4) = character where difference occurs between the last two words compared, on the
- // interval [0,1] (0 for low half-word different, 1 for high half-word different).
+ // Without string compression (temp1 >> 4) = character where difference occurs between the last
+ // two words compared, in the interval [0,1].
+ // (0 for low half-word different, 1 for high half-word different).
+ // With string compression, (temp1 << 3) = byte where the difference occurs,
+ // in the interval [0,3].
- // If temp0 <= (temp1 >> 4), the difference occurs outside the remaining string data, so just
- // return length diff (out).
- __ cmp(temp0, ShifterOperand(temp1, LSR, 4));
- __ b(&end, LE);
+ // If temp0 <= (temp1 >> (kUseStringCompression ? 3 : 4)), the difference occurs outside
+ // the remaining string data, so just return length diff (out).
+ // The comparison is unsigned for string compression, otherwise signed.
+ __ cmp(temp0, ShifterOperand(temp1, LSR, mirror::kUseStringCompression ? 3 : 4));
+ __ b(&end, mirror::kUseStringCompression ? LS : LE);
// Extract the characters and calculate the difference.
+ Label uncompressed_string, continue_process;
+ if (mirror::kUseStringCompression) {
+ __ cmp(temp4, ShifterOperand(0));
+ __ b(&uncompressed_string, GE);
+ __ bic(temp1, temp1, ShifterOperand(0x7));
+ __ b(&continue_process);
+ }
+ __ Bind(&uncompressed_string);
__ bic(temp1, temp1, ShifterOperand(0xf));
+ __ Bind(&continue_process);
+
__ Lsr(temp2, temp2, temp1);
__ Lsr(IP, IP, temp1);
+ Label calculate_difference, uncompressed_string_extract_chars;
+ if (mirror::kUseStringCompression) {
+ __ cmp(temp4, ShifterOperand(0));
+ __ b(&uncompressed_string_extract_chars, GE);
+ __ ubfx(temp2, temp2, 0, 8);
+ __ ubfx(IP, IP, 0, 8);
+ __ b(&calculate_difference);
+ }
+ __ Bind(&uncompressed_string_extract_chars);
__ movt(temp2, 0);
__ movt(IP, 0);
+ __ Bind(&calculate_difference);
__ sub(out, IP, ShifterOperand(temp2));
+ __ b(&end);
+
+ if (mirror::kUseStringCompression) {
+ const size_t c_char_size = Primitive::ComponentSize(Primitive::kPrimByte);
+ DCHECK_EQ(c_char_size, 1u);
+ Label loop_arg_compressed, loop_this_compressed, find_diff;
+ // Comparison for different compression style.
+ // This part is when THIS is compressed and ARG is not.
+ __ Bind(&different_compression);
+ __ add(temp2, str, ShifterOperand(value_offset));
+ __ add(temp3, arg, ShifterOperand(value_offset));
+ __ cmp(temp4, ShifterOperand(0));
+ __ b(&loop_arg_compressed, LT);
+
+ __ Bind(&loop_this_compressed);
+ __ ldrb(IP, Address(temp2, c_char_size, Address::PostIndex));
+ __ ldrh(temp4, Address(temp3, char_size, Address::PostIndex));
+ __ cmp(IP, ShifterOperand(temp4));
+ __ b(&find_diff, NE);
+ __ subs(temp0, temp0, ShifterOperand(1));
+ __ b(&loop_this_compressed, GT);
+ __ b(&end);
+
+ // This part is when THIS is not compressed and ARG is.
+ __ Bind(&loop_arg_compressed);
+ __ ldrh(IP, Address(temp2, char_size, Address::PostIndex));
+ __ ldrb(temp4, Address(temp3, c_char_size, Address::PostIndex));
+ __ cmp(IP, ShifterOperand(temp4));
+ __ b(&find_diff, NE);
+ __ subs(temp0, temp0, ShifterOperand(1));
+ __ b(&loop_arg_compressed, GT);
+ __ b(&end);
+
+ // Calculate the difference.
+ __ Bind(&find_diff);
+ __ sub(out, IP, ShifterOperand(temp4));
+ }
__ Bind(&end);
@@ -1180,7 +1282,7 @@
Register temp1 = locations->GetTemp(1).AsRegister<Register>();
Register temp2 = locations->GetTemp(2).AsRegister<Register>();
- Label loop;
+ Label loop, preloop;
Label end;
Label return_true;
Label return_false;
@@ -1214,11 +1316,15 @@
__ ldr(temp, Address(str, count_offset));
__ ldr(temp1, Address(arg, count_offset));
// Check if lengths are equal, return false if they're not.
+ // Also compares the compression style, if differs return false.
__ cmp(temp, ShifterOperand(temp1));
__ b(&return_false, NE);
// Return true if both strings are empty.
+ if (mirror::kUseStringCompression) {
+ // Length needs to be masked out first because 0 is treated as compressed.
+ __ bic(temp, temp, ShifterOperand(0x80000000));
+ }
__ cbz(temp, &return_true);
-
// Reference equality check, return true if same reference.
__ cmp(str, ShifterOperand(arg));
__ b(&return_true, EQ);
@@ -1227,10 +1333,19 @@
DCHECK_ALIGNED(value_offset, 4);
static_assert(IsAligned<4>(kObjectAlignment), "String data must be aligned for fast compare.");
- __ LoadImmediate(temp1, value_offset);
-
+ if (mirror::kUseStringCompression) {
+ // If not compressed, directly to fast compare. Else do preprocess on length.
+ __ cmp(temp1, ShifterOperand(0));
+ __ b(&preloop, GT);
+ // Mask out compression flag and adjust length for compressed string (8-bit)
+ // as if it is a 16-bit data, new_length = (length + 1) / 2.
+ __ add(temp, temp, ShifterOperand(1));
+ __ Lsr(temp, temp, 1);
+ __ Bind(&preloop);
+ }
// Loop to compare strings 2 characters at a time starting at the front of the string.
// Ok to do this because strings with an odd length are zero-padded.
+ __ LoadImmediate(temp1, value_offset);
__ Bind(&loop);
__ ldr(out, Address(str, temp1));
__ ldr(temp2, Address(arg, temp1));
@@ -2330,22 +2445,31 @@
Register src_ptr = locations->GetTemp(1).AsRegister<Register>();
Register dst_ptr = locations->GetTemp(2).AsRegister<Register>();
- // src range to copy.
- __ add(src_ptr, srcObj, ShifterOperand(value_offset));
- __ add(src_ptr, src_ptr, ShifterOperand(srcBegin, LSL, 1));
-
+ Label done, compressed_string_loop;
// dst to be copied.
__ add(dst_ptr, dstObj, ShifterOperand(data_offset));
__ add(dst_ptr, dst_ptr, ShifterOperand(dstBegin, LSL, 1));
__ subs(num_chr, srcEnd, ShifterOperand(srcBegin));
-
- // Do the copy.
- Label loop, remainder, done;
-
// Early out for valid zero-length retrievals.
__ b(&done, EQ);
+ // src range to copy.
+ __ add(src_ptr, srcObj, ShifterOperand(value_offset));
+ Label compressed_string_preloop;
+ if (mirror::kUseStringCompression) {
+ // Location of count in string.
+ const uint32_t count_offset = mirror::String::CountOffset().Uint32Value();
+ // String's length.
+ __ ldr(IP, Address(srcObj, count_offset));
+ __ cmp(IP, ShifterOperand(0));
+ __ b(&compressed_string_preloop, LT);
+ }
+ __ add(src_ptr, src_ptr, ShifterOperand(srcBegin, LSL, 1));
+
+ // Do the copy.
+ Label loop, remainder;
+
// Save repairing the value of num_chr on the < 4 character path.
__ subs(IP, num_chr, ShifterOperand(4));
__ b(&remainder, LT);
@@ -2374,6 +2498,20 @@
__ subs(num_chr, num_chr, ShifterOperand(1));
__ strh(IP, Address(dst_ptr, char_size, Address::PostIndex));
__ b(&remainder, GT);
+ __ b(&done);
+
+ if (mirror::kUseStringCompression) {
+ const size_t c_char_size = Primitive::ComponentSize(Primitive::kPrimByte);
+ DCHECK_EQ(c_char_size, 1u);
+ // Copy loop for compressed src, copying 1 character (8-bit) to (16-bit) at a time.
+ __ Bind(&compressed_string_preloop);
+ __ add(src_ptr, src_ptr, ShifterOperand(srcBegin));
+ __ Bind(&compressed_string_loop);
+ __ ldrb(IP, Address(src_ptr, c_char_size, Address::PostIndex));
+ __ strh(IP, Address(dst_ptr, char_size, Address::PostIndex));
+ __ subs(num_chr, num_chr, ShifterOperand(1));
+ __ b(&compressed_string_loop, GT);
+ }
__ Bind(&done);
}
diff --git a/compiler/optimizing/intrinsics_arm.h b/compiler/optimizing/intrinsics_arm.h
index c671700..7f20ea4 100644
--- a/compiler/optimizing/intrinsics_arm.h
+++ b/compiler/optimizing/intrinsics_arm.h
@@ -37,7 +37,7 @@
// Define visitor methods.
-#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache, SideEffects, Exceptions) \
+#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache, SideEffects, Exceptions, ...) \
void Visit ## Name(HInvoke* invoke) OVERRIDE;
#include "intrinsics_list.h"
INTRINSICS_LIST(OPTIMIZING_INTRINSICS)
@@ -64,7 +64,7 @@
// Define visitor methods.
-#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache, SideEffects, Exceptions) \
+#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache, SideEffects, Exceptions, ...) \
void Visit ## Name(HInvoke* invoke) OVERRIDE;
#include "intrinsics_list.h"
INTRINSICS_LIST(OPTIMIZING_INTRINSICS)
diff --git a/compiler/optimizing/intrinsics_arm64.cc b/compiler/optimizing/intrinsics_arm64.cc
index ce58657..e2c1802 100644
--- a/compiler/optimizing/intrinsics_arm64.cc
+++ b/compiler/optimizing/intrinsics_arm64.cc
@@ -1223,6 +1223,11 @@
locations->AddTemp(Location::RequiresRegister());
locations->AddTemp(Location::RequiresRegister());
locations->AddTemp(Location::RequiresRegister());
+ // Need temporary registers for String compression's feature.
+ if (mirror::kUseStringCompression) {
+ locations->AddTemp(Location::RequiresRegister());
+ locations->AddTemp(Location::RequiresRegister());
+ }
locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
}
@@ -1239,10 +1244,16 @@
Register temp0 = WRegisterFrom(locations->GetTemp(0));
Register temp1 = WRegisterFrom(locations->GetTemp(1));
Register temp2 = WRegisterFrom(locations->GetTemp(2));
+ Register temp3, temp5;
+ if (mirror::kUseStringCompression) {
+ temp3 = WRegisterFrom(locations->GetTemp(3));
+ temp5 = WRegisterFrom(locations->GetTemp(4));
+ }
vixl::aarch64::Label loop;
vixl::aarch64::Label find_char_diff;
vixl::aarch64::Label end;
+ vixl::aarch64::Label different_compression;
// Get offsets of count and value fields within a string object.
const int32_t count_offset = mirror::String::CountOffset().Int32Value();
@@ -1263,9 +1274,18 @@
// Reference equality check, return 0 if same reference.
__ Subs(out, str, arg);
__ B(&end, eq);
- // Load lengths of this and argument strings.
- __ Ldr(temp0, HeapOperand(str, count_offset));
- __ Ldr(temp1, HeapOperand(arg, count_offset));
+ if (mirror::kUseStringCompression) {
+ // Load lengths of this and argument strings.
+ __ Ldr(temp3, HeapOperand(str, count_offset));
+ __ Ldr(temp5, HeapOperand(arg, count_offset));
+ // Clean out compression flag from lengths.
+ __ Bic(temp0, temp3, Operand(static_cast<int32_t>(0x80000000)));
+ __ Bic(temp1, temp5, Operand(static_cast<int32_t>(0x80000000)));
+ } else {
+ // Load lengths of this and argument strings.
+ __ Ldr(temp0, HeapOperand(str, count_offset));
+ __ Ldr(temp1, HeapOperand(arg, count_offset));
+ }
// Return zero if both strings are empty.
__ Orr(out, temp0, temp1);
__ Cbz(out, &end);
@@ -1276,8 +1296,22 @@
// Shorter string is empty?
__ Cbz(temp2, &end);
+ if (mirror::kUseStringCompression) {
+ // Check if both strings using same compression style to use this comparison loop.
+ __ Eor(temp3.W(), temp3, Operand(temp5));
+ __ Tbnz(temp3.W(), kWRegSize - 1, &different_compression);
+ }
// Store offset of string value in preparation for comparison loop.
__ Mov(temp1, value_offset);
+ if (mirror::kUseStringCompression) {
+ // For string compression, calculate the number of bytes to compare (not chars).
+ // This could be in theory exceed INT32_MAX, so treat temp2 as unsigned.
+ vixl::aarch64::Label let_it_signed;
+ __ Cmp(temp5, Operand(0));
+ __ B(lt, &let_it_signed);
+ __ Add(temp2, temp2, Operand(temp2));
+ __ Bind(&let_it_signed);
+ }
UseScratchRegisterScope scratch_scope(masm);
Register temp4 = scratch_scope.AcquireX();
@@ -1299,29 +1333,90 @@
__ Cmp(temp4, temp0);
__ B(ne, &find_char_diff);
__ Add(temp1, temp1, char_size * 4);
- __ Subs(temp2, temp2, 4);
- __ B(gt, &loop);
+ // With string compression, we have compared 8 bytes, otherwise 4 chars.
+ __ Subs(temp2, temp2, (mirror::kUseStringCompression) ? 8 : 4);
+ __ B(hi, &loop);
__ B(&end);
// Promote temp1 to an X reg, ready for EOR.
temp1 = temp1.X();
- // Find the single 16-bit character difference.
+ // Find the single character difference.
__ Bind(&find_char_diff);
// Get the bit position of the first character that differs.
__ Eor(temp1, temp0, temp4);
__ Rbit(temp1, temp1);
__ Clz(temp1, temp1);
- // If the number of 16-bit chars remaining <= the index where the difference occurs (0-3), then
+ // If the number of chars remaining <= the index where the difference occurs (0-3), then
// the difference occurs outside the remaining string data, so just return length diff (out).
- __ Cmp(temp2, Operand(temp1.W(), LSR, 4));
- __ B(le, &end);
+ // Unlike ARM, we're doing the comparison in one go here, without the subtraction at the
+ // find_char_diff_2nd_cmp path, so it doesn't matter whether the comparison is signed or
+ // unsigned when string compression is disabled.
+ // When it's enabled, the comparison must be unsigned.
+ __ Cmp(temp2, Operand(temp1.W(), LSR, (mirror::kUseStringCompression) ? 3 : 4));
+ __ B(ls, &end);
// Extract the characters and calculate the difference.
+ vixl::aarch64::Label uncompressed_string, continue_process;
+ if (mirror:: kUseStringCompression) {
+ __ Tbz(temp5, kWRegSize - 1, &uncompressed_string);
+ __ Bic(temp1, temp1, 0x7);
+ __ B(&continue_process);
+ }
+ __ Bind(&uncompressed_string);
__ Bic(temp1, temp1, 0xf);
+ __ Bind(&continue_process);
+
__ Lsr(temp0, temp0, temp1);
__ Lsr(temp4, temp4, temp1);
+ vixl::aarch64::Label uncompressed_string_extract_chars;
+ if (mirror::kUseStringCompression) {
+ __ Tbz(temp5, kWRegSize - 1, &uncompressed_string_extract_chars);
+ __ And(temp4, temp4, 0xff);
+ __ Sub(out, temp4.W(), Operand(temp0.W(), UXTB));
+ __ B(&end);
+ }
+ __ Bind(&uncompressed_string_extract_chars);
__ And(temp4, temp4, 0xffff);
__ Sub(out, temp4.W(), Operand(temp0.W(), UXTH));
+ __ B(&end);
+
+ if (mirror::kUseStringCompression) {
+ vixl::aarch64::Label loop_this_compressed, loop_arg_compressed, find_diff;
+ const size_t c_char_size = Primitive::ComponentSize(Primitive::kPrimByte);
+ DCHECK_EQ(c_char_size, 1u);
+ temp0 = temp0.W();
+ temp1 = temp1.W();
+ // Comparison for different compression style.
+ // This part is when THIS is compressed and ARG is not.
+ __ Bind(&different_compression);
+ __ Add(temp0, str, Operand(value_offset));
+ __ Add(temp1, arg, Operand(value_offset));
+ __ Cmp(temp5, Operand(0));
+ __ B(lt, &loop_arg_compressed);
+
+ __ Bind(&loop_this_compressed);
+ __ Ldrb(temp3, MemOperand(temp0.X(), c_char_size, PostIndex));
+ __ Ldrh(temp5, MemOperand(temp1.X(), char_size, PostIndex));
+ __ Cmp(temp3, Operand(temp5));
+ __ B(ne, &find_diff);
+ __ Subs(temp2, temp2, 1);
+ __ B(gt, &loop_this_compressed);
+ __ B(&end);
+
+ // This part is when THIS is not compressed and ARG is.
+ __ Bind(&loop_arg_compressed);
+ __ Ldrh(temp3, MemOperand(temp0.X(), char_size, PostIndex));
+ __ Ldrb(temp5, MemOperand(temp1.X(), c_char_size, PostIndex));
+ __ Cmp(temp3, Operand(temp5));
+ __ B(ne, &find_diff);
+ __ Subs(temp2, temp2, 1);
+ __ B(gt, &loop_arg_compressed);
+ __ B(&end);
+
+ // Calculate the difference.
+ __ Bind(&find_diff);
+ __ Sub(out, temp3.W(), Operand(temp5.W(), UXTH));
+ }
__ Bind(&end);
@@ -1356,7 +1451,7 @@
Register temp1 = WRegisterFrom(locations->GetTemp(0));
Register temp2 = WRegisterFrom(locations->GetTemp(1));
- vixl::aarch64::Label loop;
+ vixl::aarch64::Label loop, preloop;
vixl::aarch64::Label end;
vixl::aarch64::Label return_true;
vixl::aarch64::Label return_false;
@@ -1394,22 +1489,37 @@
__ Ldr(temp, MemOperand(str.X(), count_offset));
__ Ldr(temp1, MemOperand(arg.X(), count_offset));
// Check if lengths are equal, return false if they're not.
+ // Also compares the compression style, if differs return false.
__ Cmp(temp, temp1);
__ B(&return_false, ne);
- // Store offset of string value in preparation for comparison loop
- __ Mov(temp1, value_offset);
// Return true if both strings are empty.
+ if (mirror::kUseStringCompression) {
+ // Length needs to be masked out first because 0 is treated as compressed.
+ __ Bic(temp, temp, Operand(static_cast<int32_t>(0x80000000)));
+ }
__ Cbz(temp, &return_true);
// Assertions that must hold in order to compare strings 4 characters at a time.
DCHECK_ALIGNED(value_offset, 8);
static_assert(IsAligned<8>(kObjectAlignment), "String of odd length is not zero padded");
+ if (mirror::kUseStringCompression) {
+ // If not compressed, directly to fast compare. Else do preprocess on length.
+ __ Cmp(temp1, Operand(0));
+ __ B(&preloop, gt);
+ // Mask out compression flag and adjust length for compressed string (8-bit)
+ // as if it is a 16-bit data, new_length = (length + 1) / 2
+ __ Add(temp, temp, 1);
+ __ Lsr(temp, temp, 1);
+ }
+
temp1 = temp1.X();
temp2 = temp2.X();
-
// Loop to compare strings 4 characters at a time starting at the beginning of the string.
// Ok to do this because strings are zero-padded to be 8-byte aligned.
+ // Store offset of string value in preparation for comparison loop
+ __ Bind(&preloop);
+ __ Mov(temp1, value_offset);
__ Bind(&loop);
__ Ldr(out, MemOperand(str.X(), temp1));
__ Ldr(temp2, MemOperand(arg.X(), temp1));
@@ -1773,6 +1883,10 @@
locations->AddTemp(Location::RequiresRegister());
locations->AddTemp(Location::RequiresRegister());
locations->AddTemp(Location::RequiresRegister());
+ // Need temporary register for String compression feature.
+ if (mirror::kUseStringCompression) {
+ locations->AddTemp(Location::RequiresRegister());
+ }
}
void IntrinsicCodeGeneratorARM64::VisitStringGetCharsNoCheck(HInvoke* invoke) {
@@ -1800,29 +1914,41 @@
Register src_ptr = XRegisterFrom(locations->GetTemp(0));
Register num_chr = XRegisterFrom(locations->GetTemp(1));
Register tmp1 = XRegisterFrom(locations->GetTemp(2));
+ Register tmp3;
+ if (mirror::kUseStringCompression) {
+ tmp3 = WRegisterFrom(locations->GetTemp(3));
+ }
UseScratchRegisterScope temps(masm);
Register dst_ptr = temps.AcquireX();
Register tmp2 = temps.AcquireX();
- // src address to copy from.
- __ Add(src_ptr, srcObj, Operand(value_offset));
- __ Add(src_ptr, src_ptr, Operand(srcBegin, LSL, 1));
+ vixl::aarch64::Label done;
+ vixl::aarch64::Label compressed_string_loop;
+ __ Sub(num_chr, srcEnd, srcBegin);
+ // Early out for valid zero-length retrievals.
+ __ Cbz(num_chr, &done);
// dst address start to copy to.
__ Add(dst_ptr, dstObj, Operand(data_offset));
__ Add(dst_ptr, dst_ptr, Operand(dstBegin, LSL, 1));
- __ Sub(num_chr, srcEnd, srcBegin);
+ // src address to copy from.
+ __ Add(src_ptr, srcObj, Operand(value_offset));
+ vixl::aarch64::Label compressed_string_preloop;
+ if (mirror::kUseStringCompression) {
+ // Location of count in string.
+ const uint32_t count_offset = mirror::String::CountOffset().Uint32Value();
+ // String's length.
+ __ Ldr(tmp3, MemOperand(srcObj, count_offset));
+ __ Tbnz(tmp3, kWRegSize - 1, &compressed_string_preloop);
+ }
+ __ Add(src_ptr, src_ptr, Operand(srcBegin, LSL, 1));
// Do the copy.
vixl::aarch64::Label loop;
- vixl::aarch64::Label done;
vixl::aarch64::Label remainder;
- // Early out for valid zero-length retrievals.
- __ Cbz(num_chr, &done);
-
// Save repairing the value of num_chr on the < 8 character path.
__ Subs(tmp1, num_chr, 8);
__ B(lt, &remainder);
@@ -1848,6 +1974,20 @@
__ Subs(num_chr, num_chr, 1);
__ Strh(tmp1, MemOperand(dst_ptr, char_size, PostIndex));
__ B(gt, &remainder);
+ __ B(&done);
+
+ if (mirror::kUseStringCompression) {
+ const size_t c_char_size = Primitive::ComponentSize(Primitive::kPrimByte);
+ DCHECK_EQ(c_char_size, 1u);
+ __ Bind(&compressed_string_preloop);
+ __ Add(src_ptr, src_ptr, Operand(srcBegin));
+ // Copy loop for compressed src, copying 1 character (8-bit) to (16-bit) at a time.
+ __ Bind(&compressed_string_loop);
+ __ Ldrb(tmp1, MemOperand(src_ptr, c_char_size, PostIndex));
+ __ Strh(tmp1, MemOperand(dst_ptr, char_size, PostIndex));
+ __ Subs(num_chr, num_chr, Operand(1));
+ __ B(gt, &compressed_string_loop);
+ }
__ Bind(&done);
}
diff --git a/compiler/optimizing/intrinsics_arm64.h b/compiler/optimizing/intrinsics_arm64.h
index 5251536..28e41cb 100644
--- a/compiler/optimizing/intrinsics_arm64.h
+++ b/compiler/optimizing/intrinsics_arm64.h
@@ -42,7 +42,7 @@
// Define visitor methods.
-#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache, SideEffects, Exceptions) \
+#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache, SideEffects, Exceptions, ...) \
void Visit ## Name(HInvoke* invoke) OVERRIDE;
#include "intrinsics_list.h"
INTRINSICS_LIST(OPTIMIZING_INTRINSICS)
@@ -66,7 +66,7 @@
// Define visitor methods.
-#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache, SideEffects, Exceptions) \
+#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache, SideEffects, Exceptions, ...) \
void Visit ## Name(HInvoke* invoke) OVERRIDE;
#include "intrinsics_list.h"
INTRINSICS_LIST(OPTIMIZING_INTRINSICS)
diff --git a/compiler/optimizing/intrinsics_list.h b/compiler/optimizing/intrinsics_list.h
deleted file mode 100644
index db60238..0000000
--- a/compiler/optimizing/intrinsics_list.h
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ART_COMPILER_OPTIMIZING_INTRINSICS_LIST_H_
-#define ART_COMPILER_OPTIMIZING_INTRINSICS_LIST_H_
-
-// All intrinsics supported by the optimizing compiler. Format is name, then whether it is expected
-// to be a HInvokeStaticOrDirect node (compared to HInvokeVirtual), then whether it requires an
-// environment, may have side effects, or may throw exceptions.
-
-#define INTRINSICS_LIST(V) \
- V(DoubleDoubleToRawLongBits, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
- V(DoubleDoubleToLongBits, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
- V(DoubleIsInfinite, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
- V(DoubleIsNaN, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
- V(DoubleLongBitsToDouble, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
- V(FloatFloatToRawIntBits, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
- V(FloatFloatToIntBits, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
- V(FloatIsInfinite, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
- V(FloatIsNaN, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
- V(FloatIntBitsToFloat, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
- V(IntegerReverse, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
- V(IntegerReverseBytes, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
- V(IntegerBitCount, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
- V(IntegerCompare, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
- V(IntegerHighestOneBit, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
- V(IntegerLowestOneBit, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
- V(IntegerNumberOfLeadingZeros, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
- V(IntegerNumberOfTrailingZeros, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
- V(IntegerRotateRight, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
- V(IntegerRotateLeft, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
- V(IntegerSignum, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
- V(LongReverse, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
- V(LongReverseBytes, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
- V(LongBitCount, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
- V(LongCompare, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
- V(LongHighestOneBit, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
- V(LongLowestOneBit, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
- V(LongNumberOfLeadingZeros, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
- V(LongNumberOfTrailingZeros, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
- V(LongRotateRight, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
- V(LongRotateLeft, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
- V(LongSignum, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
- V(ShortReverseBytes, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
- V(MathAbsDouble, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
- V(MathAbsFloat, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
- V(MathAbsLong, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
- V(MathAbsInt, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
- V(MathMinDoubleDouble, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
- V(MathMinFloatFloat, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
- V(MathMinLongLong, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
- V(MathMinIntInt, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
- V(MathMaxDoubleDouble, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
- V(MathMaxFloatFloat, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
- V(MathMaxLongLong, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
- V(MathMaxIntInt, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
- V(MathCos, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
- V(MathSin, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
- V(MathAcos, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
- V(MathAsin, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
- V(MathAtan, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
- V(MathAtan2, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
- V(MathCbrt, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
- V(MathCosh, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
- V(MathExp, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
- V(MathExpm1, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
- V(MathHypot, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
- V(MathLog, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
- V(MathLog10, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
- V(MathNextAfter, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
- V(MathSinh, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
- V(MathTan, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
- V(MathTanh, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
- V(MathSqrt, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
- V(MathCeil, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
- V(MathFloor, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
- V(MathRint, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
- V(MathRoundDouble, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
- V(MathRoundFloat, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
- V(SystemArrayCopyChar, kStatic, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow) \
- V(SystemArrayCopy, kStatic, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow) \
- V(ThreadCurrentThread, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \
- V(MemoryPeekByte, kStatic, kNeedsEnvironmentOrCache, kReadSideEffects, kCanThrow) \
- V(MemoryPeekIntNative, kStatic, kNeedsEnvironmentOrCache, kReadSideEffects, kCanThrow) \
- V(MemoryPeekLongNative, kStatic, kNeedsEnvironmentOrCache, kReadSideEffects, kCanThrow) \
- V(MemoryPeekShortNative, kStatic, kNeedsEnvironmentOrCache, kReadSideEffects, kCanThrow) \
- V(MemoryPokeByte, kStatic, kNeedsEnvironmentOrCache, kWriteSideEffects, kCanThrow) \
- V(MemoryPokeIntNative, kStatic, kNeedsEnvironmentOrCache, kWriteSideEffects, kCanThrow) \
- V(MemoryPokeLongNative, kStatic, kNeedsEnvironmentOrCache, kWriteSideEffects, kCanThrow) \
- V(MemoryPokeShortNative, kStatic, kNeedsEnvironmentOrCache, kWriteSideEffects, kCanThrow) \
- V(StringCharAt, kDirect, kNeedsEnvironmentOrCache, kReadSideEffects, kCanThrow) \
- V(StringCompareTo, kDirect, kNeedsEnvironmentOrCache, kReadSideEffects, kCanThrow) \
- V(StringEquals, kDirect, kNeedsEnvironmentOrCache, kReadSideEffects, kCanThrow) \
- V(StringGetCharsNoCheck, kDirect, kNeedsEnvironmentOrCache, kReadSideEffects, kCanThrow) \
- V(StringIndexOf, kDirect, kNeedsEnvironmentOrCache, kReadSideEffects, kCanThrow) \
- V(StringIndexOfAfter, kDirect, kNeedsEnvironmentOrCache, kReadSideEffects, kCanThrow) \
- V(StringIsEmpty, kDirect, kNeedsEnvironmentOrCache, kReadSideEffects, kNoThrow) \
- V(StringLength, kDirect, kNeedsEnvironmentOrCache, kReadSideEffects, kNoThrow) \
- V(StringNewStringFromBytes, kStatic, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow) \
- V(StringNewStringFromChars, kStatic, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow) \
- V(StringNewStringFromString, kStatic, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow) \
- V(UnsafeCASInt, kDirect, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow) \
- V(UnsafeCASLong, kDirect, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow) \
- V(UnsafeCASObject, kDirect, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow) \
- V(UnsafeGet, kDirect, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow) \
- V(UnsafeGetVolatile, kDirect, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow) \
- V(UnsafeGetObject, kDirect, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow) \
- V(UnsafeGetObjectVolatile, kDirect, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow) \
- V(UnsafeGetLong, kDirect, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow) \
- V(UnsafeGetLongVolatile, kDirect, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow) \
- V(UnsafePut, kDirect, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow) \
- V(UnsafePutOrdered, kDirect, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow) \
- V(UnsafePutVolatile, kDirect, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow) \
- V(UnsafePutObject, kDirect, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow) \
- V(UnsafePutObjectOrdered, kDirect, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow) \
- V(UnsafePutObjectVolatile, kDirect, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow) \
- V(UnsafePutLong, kDirect, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow) \
- V(UnsafePutLongOrdered, kDirect, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow) \
- V(UnsafePutLongVolatile, kDirect, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow) \
- V(UnsafeGetAndAddInt, kDirect, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow) \
- V(UnsafeGetAndAddLong, kDirect, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow) \
- V(UnsafeGetAndSetInt, kDirect, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow) \
- V(UnsafeGetAndSetLong, kDirect, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow) \
- V(UnsafeGetAndSetObject, kDirect, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow) \
- V(UnsafeLoadFence, kDirect, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow) \
- V(UnsafeStoreFence, kDirect, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow) \
- V(UnsafeFullFence, kDirect, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow) \
- V(ReferenceGetReferent, kDirect, kNeedsEnvironmentOrCache, kAllSideEffects, kCanThrow)
-
-#endif // ART_COMPILER_OPTIMIZING_INTRINSICS_LIST_H_
-#undef ART_COMPILER_OPTIMIZING_INTRINSICS_LIST_H_ // #define is only for lint.
diff --git a/compiler/optimizing/intrinsics_mips.h b/compiler/optimizing/intrinsics_mips.h
index 575a7d0..e134cb8 100644
--- a/compiler/optimizing/intrinsics_mips.h
+++ b/compiler/optimizing/intrinsics_mips.h
@@ -36,7 +36,7 @@
// Define visitor methods.
-#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache, SideEffects, Exceptions) \
+#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache, SideEffects, Exceptions, ...) \
void Visit ## Name(HInvoke* invoke) OVERRIDE;
#include "intrinsics_list.h"
INTRINSICS_LIST(OPTIMIZING_INTRINSICS)
@@ -60,7 +60,7 @@
// Define visitor methods.
-#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache, SideEffects, Exceptions) \
+#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache, SideEffects, Exceptions, ...) \
void Visit ## Name(HInvoke* invoke) OVERRIDE;
#include "intrinsics_list.h"
INTRINSICS_LIST(OPTIMIZING_INTRINSICS)
diff --git a/compiler/optimizing/intrinsics_mips64.h b/compiler/optimizing/intrinsics_mips64.h
index 4137fbd..5b95c26 100644
--- a/compiler/optimizing/intrinsics_mips64.h
+++ b/compiler/optimizing/intrinsics_mips64.h
@@ -36,7 +36,7 @@
// Define visitor methods.
-#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache, SideEffects, Exceptions) \
+#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache, SideEffects, Exceptions, ...) \
void Visit ## Name(HInvoke* invoke) OVERRIDE;
#include "intrinsics_list.h"
INTRINSICS_LIST(OPTIMIZING_INTRINSICS)
@@ -60,7 +60,7 @@
// Define visitor methods.
-#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache, SideEffects, Exceptions) \
+#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache, SideEffects, Exceptions, ...) \
void Visit ## Name(HInvoke* invoke) OVERRIDE;
#include "intrinsics_list.h"
INTRINSICS_LIST(OPTIMIZING_INTRINSICS)
diff --git a/compiler/optimizing/intrinsics_x86.cc b/compiler/optimizing/intrinsics_x86.cc
index e61aba0..f41e4d9 100644
--- a/compiler/optimizing/intrinsics_x86.cc
+++ b/compiler/optimizing/intrinsics_x86.cc
@@ -1401,23 +1401,39 @@
__ cmpl(str, arg);
__ j(kEqual, &return_true);
- // Load length of receiver string.
+ // Load length and compression flag of receiver string.
__ movl(ecx, Address(str, count_offset));
- // Check if lengths are equal, return false if they're not.
+ // Check if lengths and compression flags are equal, return false if they're not.
+ // Two identical strings will always have same compression style since
+ // compression style is decided on alloc.
__ cmpl(ecx, Address(arg, count_offset));
__ j(kNotEqual, &return_false);
- // Return true if both strings are empty.
- __ jecxz(&return_true);
+ if (mirror::kUseStringCompression) {
+ NearLabel string_uncompressed;
+ // Differ cases into both compressed or both uncompressed. Different compression style
+ // is cut above.
+ __ cmpl(ecx, Immediate(0));
+ __ j(kGreaterEqual, &string_uncompressed);
+ // Divide string length by 2, rounding up, and continue as if uncompressed.
+ // Merge clearing the compression flag (+0x80000000) with +1 for rounding.
+ __ addl(ecx, Immediate(0x80000001));
+ __ shrl(ecx, Immediate(1));
+ __ Bind(&string_uncompressed);
+ }
+ // Return true if strings are empty.
+ __ jecxz(&return_true);
// Load starting addresses of string values into ESI/EDI as required for repe_cmpsl instruction.
__ leal(esi, Address(str, value_offset));
__ leal(edi, Address(arg, value_offset));
- // Divide string length by 2 to compare characters 2 at a time and adjust for odd lengths.
+ // Divide string length by 2 to compare characters 2 at a time and adjust for lengths not
+ // divisible by 2.
__ addl(ecx, Immediate(1));
__ shrl(ecx, Immediate(1));
- // Assertions that must hold in order to compare strings 2 characters at a time.
+ // Assertions that must hold in order to compare strings 2 characters (uncompressed)
+ // or 4 characters (compressed) at a time.
DCHECK_ALIGNED(value_offset, 4);
static_assert(IsAligned<4>(kObjectAlignment), "String of odd length is not zero padded");
@@ -1461,6 +1477,10 @@
locations->AddTemp(Location::RegisterLocation(ECX));
// Need another temporary to be able to compute the result.
locations->AddTemp(Location::RequiresRegister());
+ if (mirror::kUseStringCompression) {
+ // Need another temporary to be able to save unflagged string length.
+ locations->AddTemp(Location::RequiresRegister());
+ }
}
static void GenerateStringIndexOf(HInvoke* invoke,
@@ -1478,6 +1498,8 @@
Register counter = locations->GetTemp(0).AsRegister<Register>();
Register string_length = locations->GetTemp(1).AsRegister<Register>();
Register out = locations->Out().AsRegister<Register>();
+ // Only used when string compression feature is on.
+ Register string_length_flagged;
// Check our assumptions for registers.
DCHECK_EQ(string_obj, EDI);
@@ -1515,6 +1537,12 @@
// Load string length, i.e., the count field of the string.
__ movl(string_length, Address(string_obj, count_offset));
+ if (mirror::kUseStringCompression) {
+ string_length_flagged = locations->GetTemp(2).AsRegister<Register>();
+ __ movl(string_length_flagged, string_length);
+ // Mask out first bit used as compression flag.
+ __ andl(string_length, Immediate(INT32_MAX));
+ }
// Do a zero-length check.
// TODO: Support jecxz.
@@ -1540,20 +1568,50 @@
__ cmpl(start_index, Immediate(0));
__ cmovl(kGreater, counter, start_index);
- // Move to the start of the string: string_obj + value_offset + 2 * start_index.
- __ leal(string_obj, Address(string_obj, counter, ScaleFactor::TIMES_2, value_offset));
+ if (mirror::kUseStringCompression) {
+ NearLabel modify_counter, offset_uncompressed_label;
+ __ cmpl(string_length_flagged, Immediate(0));
+ __ j(kGreaterEqual, &offset_uncompressed_label);
+ // Move to the start of the string: string_obj + value_offset + start_index.
+ __ leal(string_obj, Address(string_obj, counter, ScaleFactor::TIMES_1, value_offset));
+ __ jmp(&modify_counter);
- // Now update ecx (the repne scasw work counter). We have string.length - start_index left to
- // compare.
+ // Move to the start of the string: string_obj + value_offset + 2 * start_index.
+ __ Bind(&offset_uncompressed_label);
+ __ leal(string_obj, Address(string_obj, counter, ScaleFactor::TIMES_2, value_offset));
+
+ // Now update ecx (the repne scasw work counter). We have string.length - start_index left to
+ // compare.
+ __ Bind(&modify_counter);
+ } else {
+ __ leal(string_obj, Address(string_obj, counter, ScaleFactor::TIMES_2, value_offset));
+ }
__ negl(counter);
__ leal(counter, Address(string_length, counter, ScaleFactor::TIMES_1, 0));
}
- // Everything is set up for repne scasw:
- // * Comparison address in EDI.
- // * Counter in ECX.
- __ repne_scasw();
+ if (mirror::kUseStringCompression) {
+ NearLabel uncompressed_string_comparison;
+ NearLabel comparison_done;
+ __ cmpl(string_length_flagged, Immediate(0));
+ __ j(kGreater, &uncompressed_string_comparison);
+ // Check if EAX (search_value) is ASCII.
+ __ cmpl(search_value, Immediate(127));
+ __ j(kGreater, ¬_found_label);
+ // Comparing byte-per-byte.
+ __ repne_scasb();
+ __ jmp(&comparison_done);
+
+ // Everything is set up for repne scasw:
+ // * Comparison address in EDI.
+ // * Counter in ECX.
+ __ Bind(&uncompressed_string_comparison);
+ __ repne_scasw();
+ __ Bind(&comparison_done);
+ } else {
+ __ repne_scasw();
+ }
// Did we find a match?
__ j(kNotEqual, ¬_found_label);
@@ -1706,38 +1764,64 @@
const size_t char_size = Primitive::ComponentSize(Primitive::kPrimChar);
DCHECK_EQ(char_size, 2u);
- // Compute the address of the destination buffer.
- __ leal(EDI, Address(dst, dstBegin, ScaleFactor::TIMES_2, data_offset));
-
- // Compute the address of the source string.
- if (srcBegin.IsConstant()) {
- // Compute the address of the source string by adding the number of chars from
- // the source beginning to the value offset of a string.
- __ leal(ESI, Address(obj, srcBegin_value * char_size + value_offset));
- } else {
- __ leal(ESI, Address(obj, srcBegin.AsRegister<Register>(),
- ScaleFactor::TIMES_2, value_offset));
- }
-
// Compute the number of chars (words) to move.
- // Now is the time to save ECX, since we don't know if it will be used later.
+ // Save ECX, since we don't know if it will be used later.
__ pushl(ECX);
int stack_adjust = kX86WordSize;
__ cfi().AdjustCFAOffset(stack_adjust);
DCHECK_EQ(srcEnd, ECX);
if (srcBegin.IsConstant()) {
- if (srcBegin_value != 0) {
- __ subl(ECX, Immediate(srcBegin_value));
- }
+ __ subl(ECX, Immediate(srcBegin_value));
} else {
DCHECK(srcBegin.IsRegister());
__ subl(ECX, srcBegin.AsRegister<Register>());
}
- // Do the move.
+ NearLabel done;
+ if (mirror::kUseStringCompression) {
+ // Location of count in string
+ const uint32_t count_offset = mirror::String::CountOffset().Uint32Value();
+ const size_t c_char_size = Primitive::ComponentSize(Primitive::kPrimByte);
+ DCHECK_EQ(c_char_size, 1u);
+ __ pushl(EAX);
+ __ cfi().AdjustCFAOffset(stack_adjust);
+
+ NearLabel copy_loop, copy_uncompressed;
+ __ cmpl(Address(obj, count_offset), Immediate(0));
+ __ j(kGreaterEqual, ©_uncompressed);
+ // Compute the address of the source string by adding the number of chars from
+ // the source beginning to the value offset of a string.
+ __ leal(ESI, CodeGeneratorX86::ArrayAddress(obj, srcBegin, TIMES_1, value_offset));
+
+ // Start the loop to copy String's value to Array of Char.
+ __ leal(EDI, Address(dst, dstBegin, ScaleFactor::TIMES_2, data_offset));
+ __ Bind(©_loop);
+ __ jecxz(&done);
+ // Use EAX temporary (convert byte from ESI to word).
+ // TODO: Use LODSB/STOSW (not supported by X86Assembler) with AH initialized to 0.
+ __ movzxb(EAX, Address(ESI, 0));
+ __ movw(Address(EDI, 0), EAX);
+ __ leal(EDI, Address(EDI, char_size));
+ __ leal(ESI, Address(ESI, c_char_size));
+ // TODO: Add support for LOOP to X86Assembler.
+ __ subl(ECX, Immediate(1));
+ __ jmp(©_loop);
+ __ Bind(©_uncompressed);
+ }
+
+ // Do the copy for uncompressed string.
+ // Compute the address of the destination buffer.
+ __ leal(EDI, Address(dst, dstBegin, ScaleFactor::TIMES_2, data_offset));
+ __ leal(ESI, CodeGeneratorX86::ArrayAddress(obj, srcBegin, TIMES_2, value_offset));
__ rep_movsw();
- // And restore ECX.
+ __ Bind(&done);
+ if (mirror::kUseStringCompression) {
+ // Restore EAX.
+ __ popl(EAX);
+ __ cfi().AdjustCFAOffset(-stack_adjust);
+ }
+ // Restore ECX.
__ popl(ECX);
__ cfi().AdjustCFAOffset(-stack_adjust);
}
diff --git a/compiler/optimizing/intrinsics_x86.h b/compiler/optimizing/intrinsics_x86.h
index 08bd197..3743cb1 100644
--- a/compiler/optimizing/intrinsics_x86.h
+++ b/compiler/optimizing/intrinsics_x86.h
@@ -36,7 +36,7 @@
// Define visitor methods.
-#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache, SideEffects, Exceptions) \
+#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache, SideEffects, Exceptions, ...) \
void Visit ## Name(HInvoke* invoke) OVERRIDE;
#include "intrinsics_list.h"
INTRINSICS_LIST(OPTIMIZING_INTRINSICS)
@@ -61,7 +61,7 @@
// Define visitor methods.
-#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache, SideEffects, Exceptions) \
+#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache, SideEffects, Exceptions, ...) \
void Visit ## Name(HInvoke* invoke) OVERRIDE;
#include "intrinsics_list.h"
INTRINSICS_LIST(OPTIMIZING_INTRINSICS)
diff --git a/compiler/optimizing/intrinsics_x86_64.cc b/compiler/optimizing/intrinsics_x86_64.cc
index 0f31fab..4b0afca 100644
--- a/compiler/optimizing/intrinsics_x86_64.cc
+++ b/compiler/optimizing/intrinsics_x86_64.cc
@@ -1568,14 +1568,27 @@
__ cmpl(str, arg);
__ j(kEqual, &return_true);
- // Load length of receiver string.
+ // Load length and compression flag of receiver string.
__ movl(rcx, Address(str, count_offset));
- // Check if lengths are equal, return false if they're not.
+ // Check if lengths and compressiond flags are equal, return false if they're not.
+ // Two identical strings will always have same compression style since
+ // compression style is decided on alloc.
__ cmpl(rcx, Address(arg, count_offset));
__ j(kNotEqual, &return_false);
+
+ if (mirror::kUseStringCompression) {
+ NearLabel string_uncompressed;
+ // Both string are compressed.
+ __ cmpl(rcx, Immediate(0));
+ __ j(kGreaterEqual, &string_uncompressed);
+ // Divide string length by 2, rounding up, and continue as if uncompressed.
+ // Merge clearing the compression flag with +1 for rounding.
+ __ addl(rcx, Immediate(static_cast<int32_t>(0x80000001)));
+ __ shrl(rcx, Immediate(1));
+ __ Bind(&string_uncompressed);
+ }
// Return true if both strings are empty.
__ jrcxz(&return_true);
-
// Load starting addresses of string values into RSI/RDI as required for repe_cmpsq instruction.
__ leal(rsi, Address(str, value_offset));
__ leal(rdi, Address(arg, value_offset));
@@ -1584,7 +1597,8 @@
__ addl(rcx, Immediate(3));
__ shrl(rcx, Immediate(2));
- // Assertions that must hold in order to compare strings 4 characters at a time.
+ // Assertions that must hold in order to compare strings 4 characters (uncompressed)
+ // or 8 characters (compressed) at a time.
DCHECK_ALIGNED(value_offset, 8);
static_assert(IsAligned<8>(kObjectAlignment), "String is not zero padded");
@@ -1674,7 +1688,8 @@
__ j(kAbove, slow_path->GetEntryLabel());
}
- // From here down, we know that we are looking for a char that fits in 16 bits.
+ // From here down, we know that we are looking for a char that fits in
+ // 16 bits (uncompressed) or 8 bits (compressed).
// Location of reference to data array within the String object.
int32_t value_offset = mirror::String::ValueOffset().Int32Value();
// Location of count within the String object.
@@ -1682,6 +1697,12 @@
// Load string length, i.e., the count field of the string.
__ movl(string_length, Address(string_obj, count_offset));
+ if (mirror::kUseStringCompression) {
+ // Use TMP to keep string_length_flagged.
+ __ movl(CpuRegister(TMP), string_length);
+ // Mask out first bit used as compression flag.
+ __ andl(string_length, Immediate(INT32_MAX));
+ }
// Do a length check.
// TODO: Support jecxz.
@@ -1692,7 +1713,6 @@
if (start_at_zero) {
// Number of chars to scan is the same as the string length.
__ movl(counter, string_length);
-
// Move to the start of the string.
__ addq(string_obj, Immediate(value_offset));
} else {
@@ -1707,19 +1727,44 @@
__ cmpl(start_index, Immediate(0));
__ cmov(kGreater, counter, start_index, /* is64bit */ false); // 32-bit copy is enough.
- // Move to the start of the string: string_obj + value_offset + 2 * start_index.
- __ leaq(string_obj, Address(string_obj, counter, ScaleFactor::TIMES_2, value_offset));
-
+ if (mirror::kUseStringCompression) {
+ NearLabel modify_counter, offset_uncompressed_label;
+ __ cmpl(CpuRegister(TMP), Immediate(0));
+ __ j(kGreaterEqual, &offset_uncompressed_label);
+ __ leaq(string_obj, Address(string_obj, counter, ScaleFactor::TIMES_1, value_offset));
+ __ jmp(&modify_counter);
+ // Move to the start of the string: string_obj + value_offset + 2 * start_index.
+ __ Bind(&offset_uncompressed_label);
+ __ leaq(string_obj, Address(string_obj, counter, ScaleFactor::TIMES_2, value_offset));
+ __ Bind(&modify_counter);
+ } else {
+ __ leaq(string_obj, Address(string_obj, counter, ScaleFactor::TIMES_2, value_offset));
+ }
// Now update ecx, the work counter: it's gonna be string.length - start_index.
__ negq(counter); // Needs to be 64-bit negation, as the address computation is 64-bit.
__ leaq(counter, Address(string_length, counter, ScaleFactor::TIMES_1, 0));
}
- // Everything is set up for repne scasw:
- // * Comparison address in RDI.
- // * Counter in ECX.
- __ repne_scasw();
-
+ if (mirror::kUseStringCompression) {
+ NearLabel uncompressed_string_comparison;
+ NearLabel comparison_done;
+ __ cmpl(CpuRegister(TMP), Immediate(0));
+ __ j(kGreater, &uncompressed_string_comparison);
+ // Check if RAX (search_value) is ASCII.
+ __ cmpl(search_value, Immediate(127));
+ __ j(kGreater, ¬_found_label);
+ // Comparing byte-per-byte.
+ __ repne_scasb();
+ __ jmp(&comparison_done);
+ // Everything is set up for repne scasw:
+ // * Comparison address in RDI.
+ // * Counter in ECX.
+ __ Bind(&uncompressed_string_comparison);
+ __ repne_scasw();
+ __ Bind(&comparison_done);
+ } else {
+ __ repne_scasw();
+ }
// Did we find a match?
__ j(kNotEqual, ¬_found_label);
@@ -1871,32 +1916,54 @@
const size_t char_size = Primitive::ComponentSize(Primitive::kPrimChar);
DCHECK_EQ(char_size, 2u);
- // Compute the address of the destination buffer.
- __ leaq(CpuRegister(RDI), Address(dst, dstBegin, ScaleFactor::TIMES_2, data_offset));
-
- // Compute the address of the source string.
- if (srcBegin.IsConstant()) {
- // Compute the address of the source string by adding the number of chars from
- // the source beginning to the value offset of a string.
- __ leaq(CpuRegister(RSI), Address(obj, srcBegin_value * char_size + value_offset));
- } else {
- __ leaq(CpuRegister(RSI), Address(obj, srcBegin.AsRegister<CpuRegister>(),
- ScaleFactor::TIMES_2, value_offset));
- }
-
+ NearLabel done;
// Compute the number of chars (words) to move.
__ movl(CpuRegister(RCX), srcEnd);
if (srcBegin.IsConstant()) {
- if (srcBegin_value != 0) {
- __ subl(CpuRegister(RCX), Immediate(srcBegin_value));
- }
+ __ subl(CpuRegister(RCX), Immediate(srcBegin_value));
} else {
DCHECK(srcBegin.IsRegister());
__ subl(CpuRegister(RCX), srcBegin.AsRegister<CpuRegister>());
}
+ if (mirror::kUseStringCompression) {
+ NearLabel copy_uncompressed, copy_loop;
+ const size_t c_char_size = Primitive::ComponentSize(Primitive::kPrimByte);
+ DCHECK_EQ(c_char_size, 1u);
+ // Location of count in string.
+ const uint32_t count_offset = mirror::String::CountOffset().Uint32Value();
+ __ cmpl(Address(obj, count_offset), Immediate(0));
+ __ j(kGreaterEqual, ©_uncompressed);
+ // Compute the address of the source string by adding the number of chars from
+ // the source beginning to the value offset of a string.
+ __ leaq(CpuRegister(RSI),
+ CodeGeneratorX86_64::ArrayAddress(obj, srcBegin, TIMES_1, value_offset));
+ // Start the loop to copy String's value to Array of Char.
+ __ leaq(CpuRegister(RDI), Address(dst, dstBegin, ScaleFactor::TIMES_2, data_offset));
+
+ __ Bind(©_loop);
+ __ jrcxz(&done);
+ // Use TMP as temporary (convert byte from RSI to word).
+ // TODO: Selecting RAX as the temporary and using LODSB/STOSW.
+ __ movzxb(CpuRegister(TMP), Address(CpuRegister(RSI), 0));
+ __ movw(Address(CpuRegister(RDI), 0), CpuRegister(TMP));
+ __ leaq(CpuRegister(RDI), Address(CpuRegister(RDI), char_size));
+ __ leaq(CpuRegister(RSI), Address(CpuRegister(RSI), c_char_size));
+ // TODO: Add support for LOOP to X86_64Assembler.
+ __ subl(CpuRegister(RCX), Immediate(1));
+ __ jmp(©_loop);
+
+ __ Bind(©_uncompressed);
+ }
+
+ __ leaq(CpuRegister(RSI),
+ CodeGeneratorX86_64::ArrayAddress(obj, srcBegin, TIMES_2, value_offset));
+ // Compute the address of the destination buffer.
+ __ leaq(CpuRegister(RDI), Address(dst, dstBegin, ScaleFactor::TIMES_2, data_offset));
// Do the move.
__ rep_movsw();
+
+ __ Bind(&done);
}
static void GenPeek(LocationSummary* locations, Primitive::Type size, X86_64Assembler* assembler) {
diff --git a/compiler/optimizing/intrinsics_x86_64.h b/compiler/optimizing/intrinsics_x86_64.h
index 155ff65..97404aa 100644
--- a/compiler/optimizing/intrinsics_x86_64.h
+++ b/compiler/optimizing/intrinsics_x86_64.h
@@ -36,7 +36,7 @@
// Define visitor methods.
-#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache, SideEffects, Exceptions) \
+#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache, SideEffects, Exceptions, ...) \
void Visit ## Name(HInvoke* invoke) OVERRIDE;
#include "intrinsics_list.h"
INTRINSICS_LIST(OPTIMIZING_INTRINSICS)
@@ -61,7 +61,7 @@
// Define visitor methods.
-#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache, SideEffects, Exceptions) \
+#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache, SideEffects, Exceptions, ...) \
void Visit ## Name(HInvoke* invoke) OVERRIDE;
#include "intrinsics_list.h"
INTRINSICS_LIST(OPTIMIZING_INTRINSICS)
diff --git a/compiler/optimizing/nodes.cc b/compiler/optimizing/nodes.cc
index 9cfa89b..ef9bf23 100644
--- a/compiler/optimizing/nodes.cc
+++ b/compiler/optimizing/nodes.cc
@@ -25,7 +25,7 @@
#include "base/stl_util.h"
#include "intrinsics.h"
#include "mirror/class-inl.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
namespace art {
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index 4dc4c20..397abde 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -32,6 +32,7 @@
#include "handle.h"
#include "handle_scope.h"
#include "invoke_type.h"
+#include "intrinsics_enum.h"
#include "locations.h"
#include "method_reference.h"
#include "mirror/class.h"
@@ -3690,17 +3691,6 @@
DISALLOW_COPY_AND_ASSIGN(HNewInstance);
};
-enum class Intrinsics {
-#define OPTIMIZING_INTRINSICS(Name, IsStatic, NeedsEnvironmentOrCache, SideEffects, Exceptions) \
- k ## Name,
-#include "intrinsics_list.h"
- kNone,
- INTRINSICS_LIST(OPTIMIZING_INTRINSICS)
-#undef INTRINSICS_LIST
-#undef OPTIMIZING_INTRINSICS
-};
-std::ostream& operator<<(std::ostream& os, const Intrinsics& intrinsic);
-
enum IntrinsicNeedsEnvironmentOrCache {
kNoEnvironmentOrCache, // Intrinsic does not require an environment or dex cache.
kNeedsEnvironmentOrCache // Intrinsic requires an environment or requires a dex cache.
diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc
index c5d7611..d3a55dd 100644
--- a/compiler/optimizing/optimizing_compiler.cc
+++ b/compiler/optimizing/optimizing_compiler.cc
@@ -56,7 +56,6 @@
#include "dead_code_elimination.h"
#include "debug/elf_debug_writer.h"
#include "debug/method_debug_info.h"
-#include "dex/quick/dex_file_to_method_inliner_map.h"
#include "dex/verification_results.h"
#include "dex/verified_method.h"
#include "driver/compiler_driver-inl.h"
@@ -479,7 +478,7 @@
} else if (opt_name == InstructionSimplifier::kInstructionSimplifierPassName) {
return new (arena) InstructionSimplifier(graph, stats, pass_name.c_str());
} else if (opt_name == IntrinsicsRecognizer::kIntrinsicsRecognizerPassName) {
- return new (arena) IntrinsicsRecognizer(graph, driver, stats);
+ return new (arena) IntrinsicsRecognizer(graph, stats);
} else if (opt_name == LICM::kLoopInvariantCodeMotionPassName) {
CHECK(most_recent_side_effects != nullptr);
return new (arena) LICM(graph, *most_recent_side_effects, stats);
@@ -743,7 +742,7 @@
graph, stats, "instruction_simplifier$after_bce");
InstructionSimplifier* simplify3 = new (arena) InstructionSimplifier(
graph, stats, "instruction_simplifier$before_codegen");
- IntrinsicsRecognizer* intrinsics = new (arena) IntrinsicsRecognizer(graph, driver, stats);
+ IntrinsicsRecognizer* intrinsics = new (arena) IntrinsicsRecognizer(graph, stats);
HOptimization* optimizations1[] = {
intrinsics,
@@ -899,7 +898,7 @@
ScopedObjectAccess soa(Thread::Current());
StackHandleScope<1> hs(soa.Self());
Handle<mirror::ClassLoader> loader(hs.NewHandle(
- soa.Decode<mirror::ClassLoader*>(class_loader)));
+ soa.Decode<mirror::ClassLoader>(class_loader)));
method = compiler_driver->ResolveMethod(
soa, dex_cache, loader, &dex_compilation_unit, method_idx, invoke_type);
}
diff --git a/compiler/optimizing/optimizing_unit_test.h b/compiler/optimizing/optimizing_unit_test.h
index dd5cb1c..2a23c92 100644
--- a/compiler/optimizing/optimizing_unit_test.h
+++ b/compiler/optimizing/optimizing_unit_test.h
@@ -22,7 +22,7 @@
#include "common_compiler_test.h"
#include "dex_file.h"
#include "dex_instruction.h"
-#include "handle_scope-inl.h"
+#include "handle_scope.h"
#include "scoped_thread_state_change.h"
#include "ssa_builder.h"
#include "ssa_liveness_analysis.h"
diff --git a/compiler/optimizing/reference_type_propagation.cc b/compiler/optimizing/reference_type_propagation.cc
index 4289cf7..5a47df1 100644
--- a/compiler/optimizing/reference_type_propagation.cc
+++ b/compiler/optimizing/reference_type_propagation.cc
@@ -20,7 +20,7 @@
#include "class_linker-inl.h"
#include "mirror/class-inl.h"
#include "mirror/dex_cache.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
namespace art {
diff --git a/compiler/optimizing/sharpening.cc b/compiler/optimizing/sharpening.cc
index abec55f..a4a3e06 100644
--- a/compiler/optimizing/sharpening.cc
+++ b/compiler/optimizing/sharpening.cc
@@ -31,7 +31,7 @@
#include "mirror/string.h"
#include "nodes.h"
#include "runtime.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
namespace art {
diff --git a/dex2oat/Android.bp b/dex2oat/Android.bp
index 931bbd3..05a5d0f 100644
--- a/dex2oat/Android.bp
+++ b/dex2oat/Android.bp
@@ -31,6 +31,7 @@
// SANITIZE_TARGET mode.
// Bug: 22233158
address: false,
+ coverage: false,
},
},
},
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index 3b2715d..5d44cc1 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -49,7 +49,6 @@
#include "compiler_callbacks.h"
#include "debug/elf_debug_writer.h"
#include "debug/method_debug_info.h"
-#include "dex/quick/dex_file_to_method_inliner_map.h"
#include "dex/quick_compiler_callbacks.h"
#include "dex/verification_results.h"
#include "dex_file-inl.h"
@@ -77,7 +76,7 @@
#include "runtime.h"
#include "runtime_options.h"
#include "ScopedLocalRef.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
#include "utils.h"
#include "verifier/verifier_deps.h"
#include "well_known_classes.h"
@@ -509,7 +508,6 @@
image_patch_delta_(0),
key_value_store_(nullptr),
verification_results_(nullptr),
- method_inliner_map_(),
runtime_(nullptr),
thread_count_(sysconf(_SC_NPROCESSORS_CONF)),
start_ns_(NanoTime()),
@@ -1372,7 +1370,6 @@
verification_results_.reset(new VerificationResults(compiler_options_.get()));
callbacks_.reset(new QuickCompilerCallbacks(
verification_results_.get(),
- &method_inliner_map_,
IsBootImage() ?
CompilerCallbacks::CallbackMode::kCompileBootImage :
CompilerCallbacks::CallbackMode::kCompileApp));
@@ -1567,7 +1564,7 @@
ScopedObjectAccess soa(self);
dex_caches_.push_back(soa.AddLocalReference<jobject>(
class_linker->RegisterDexFile(*dex_file,
- soa.Decode<mirror::ClassLoader*>(class_loader_))));
+ soa.Decode<mirror::ClassLoader>(class_loader_).Decode())));
}
return true;
@@ -1632,7 +1629,6 @@
driver_.reset(new CompilerDriver(compiler_options_.get(),
verification_results_.get(),
- &method_inliner_map_,
compiler_kind_,
instruction_set_,
instruction_set_features_.get(),
@@ -2540,7 +2536,6 @@
std::unique_ptr<VerificationResults> verification_results_;
- DexFileToMethodInlinerMap method_inliner_map_;
std::unique_ptr<QuickCompilerCallbacks> callbacks_;
std::unique_ptr<Runtime> runtime_;
diff --git a/disassembler/disassembler_arm.cc b/disassembler/disassembler_arm.cc
index 925047f..30b708c 100644
--- a/disassembler/disassembler_arm.cc
+++ b/disassembler/disassembler_arm.cc
@@ -116,8 +116,7 @@
public:
CustomDisassembler(std::ostream& os, const DisassemblerOptions* options)
- // vixl::aarch32::Disassembler::~Disassembler() will delete the stream.
- : PrintDisassembler(new CustomDisassemblerStream(os, this, options)) {}
+ : PrintDisassembler(&disassembler_stream_), disassembler_stream_(os, this, options) {}
void PrintPc(uint32_t prog_ctr) OVERRIDE {
os() << "0x" << std::hex << std::setw(8) << std::setfill('0') << prog_ctr << ": ";
@@ -133,6 +132,7 @@
private:
bool is_t32_;
+ CustomDisassemblerStream disassembler_stream_;
};
void DisassemblerArm::CustomDisassembler::CustomDisassemblerStream::PrintLiteral(LocationType type,
diff --git a/imgdiag/imgdiag.cc b/imgdiag/imgdiag.cc
index 106cf2f..ace21aa 100644
--- a/imgdiag/imgdiag.cc
+++ b/imgdiag/imgdiag.cc
@@ -34,7 +34,7 @@
#include "mirror/class-inl.h"
#include "mirror/object-inl.h"
#include "image.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
#include "os.h"
#include "cmdline.h"
diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc
index d8ac581..be5224b 100644
--- a/oatdump/oatdump.cc
+++ b/oatdump/oatdump.cc
@@ -23,6 +23,7 @@
#include <set>
#include <string>
#include <unordered_map>
+#include <unordered_set>
#include <vector>
#include "arch/instruction_set_features.h"
@@ -42,7 +43,9 @@
#include "gc/space/large_object_space.h"
#include "gc/space/space-inl.h"
#include "image-inl.h"
+#include "imtable-inl.h"
#include "indenter.h"
+#include "interpreter/unstarted_runtime.h"
#include "linker/buffered_output_stream.h"
#include "linker/file_output_stream.h"
#include "mirror/array-inl.h"
@@ -55,7 +58,7 @@
#include "oat_file_manager.h"
#include "os.h"
#include "safe_map.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
#include "ScopedLocalRef.h"
#include "stack_map.h"
#include "string_reference.h"
@@ -2443,39 +2446,55 @@
return EXIT_SUCCESS;
}
-static int DumpOatWithRuntime(Runtime* runtime, OatFile* oat_file, OatDumperOptions* options,
- std::ostream* os) {
- CHECK(runtime != nullptr && oat_file != nullptr && options != nullptr);
-
+static jobject InstallOatFile(Runtime* runtime,
+ std::unique_ptr<OatFile> oat_file,
+ std::vector<const DexFile*>* class_path)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
Thread* self = Thread::Current();
CHECK(self != nullptr);
// Need well-known-classes.
WellKnownClasses::Init(self->GetJniEnv());
// Need to register dex files to get a working dex cache.
- ScopedObjectAccess soa(self);
+ OatFile* oat_file_ptr = oat_file.get();
ClassLinker* class_linker = runtime->GetClassLinker();
- runtime->GetOatFileManager().RegisterOatFile(std::unique_ptr<const OatFile>(oat_file));
- std::vector<const DexFile*> class_path;
- for (const OatFile::OatDexFile* odf : oat_file->GetOatDexFiles()) {
+ runtime->GetOatFileManager().RegisterOatFile(std::move(oat_file));
+ for (const OatFile::OatDexFile* odf : oat_file_ptr->GetOatDexFiles()) {
std::string error_msg;
const DexFile* const dex_file = OpenDexFile(odf, &error_msg);
CHECK(dex_file != nullptr) << error_msg;
class_linker->RegisterDexFile(*dex_file, nullptr);
- class_path.push_back(dex_file);
+ class_path->push_back(dex_file);
}
- // Need a class loader.
- // Fake that we're a compiler.
- jobject class_loader = class_linker->CreatePathClassLoader(self, class_path);
+ // Need a class loader. Fake that we're a compiler.
+ // Note: this will run initializers through the unstarted runtime, so make sure it's
+ // initialized.
+ interpreter::UnstartedRuntime::Initialize();
+
+ jobject class_loader = class_linker->CreatePathClassLoader(self, *class_path);
+
+ return class_loader;
+}
+
+static int DumpOatWithRuntime(Runtime* runtime,
+ std::unique_ptr<OatFile> oat_file,
+ OatDumperOptions* options,
+ std::ostream* os) {
+ CHECK(runtime != nullptr && oat_file != nullptr && options != nullptr);
+ ScopedObjectAccess soa(Thread::Current());
+
+ OatFile* oat_file_ptr = oat_file.get();
+ std::vector<const DexFile*> class_path;
+ jobject class_loader = InstallOatFile(runtime, std::move(oat_file), &class_path);
// Use the class loader while dumping.
- StackHandleScope<1> scope(self);
+ StackHandleScope<1> scope(soa.Self());
Handle<mirror::ClassLoader> loader_handle = scope.NewHandle(
- soa.Decode<mirror::ClassLoader*>(class_loader));
+ soa.Decode<mirror::ClassLoader>(class_loader));
options->class_loader_ = &loader_handle;
- OatDumper oat_dumper(*oat_file, *options);
+ OatDumper oat_dumper(*oat_file_ptr, *options);
bool success = oat_dumper.Dump(*os);
return (success) ? EXIT_SUCCESS : EXIT_FAILURE;
}
@@ -2494,23 +2513,23 @@
static int DumpOat(Runtime* runtime, const char* oat_filename, OatDumperOptions* options,
std::ostream* os) {
std::string error_msg;
- OatFile* oat_file = OatFile::Open(oat_filename,
- oat_filename,
- nullptr,
- nullptr,
- false,
- /*low_4gb*/false,
- nullptr,
- &error_msg);
+ std::unique_ptr<OatFile> oat_file(OatFile::Open(oat_filename,
+ oat_filename,
+ nullptr,
+ nullptr,
+ false,
+ /*low_4gb*/false,
+ nullptr,
+ &error_msg));
if (oat_file == nullptr) {
fprintf(stderr, "Failed to open oat file from '%s': %s\n", oat_filename, error_msg.c_str());
return EXIT_FAILURE;
}
if (runtime != nullptr) {
- return DumpOatWithRuntime(runtime, oat_file, options, os);
+ return DumpOatWithRuntime(runtime, std::move(oat_file), options, os);
} else {
- return DumpOatWithoutRuntime(oat_file, options, os);
+ return DumpOatWithoutRuntime(oat_file.get(), options, os);
}
}
@@ -2547,6 +2566,444 @@
return EXIT_SUCCESS;
}
+class IMTDumper {
+ public:
+ static bool Dump(Runtime* runtime,
+ const std::string& imt_file,
+ bool dump_imt_stats,
+ const char* oat_filename) {
+ Thread* self = Thread::Current();
+
+ ScopedObjectAccess soa(self);
+ StackHandleScope<1> scope(self);
+ MutableHandle<mirror::ClassLoader> class_loader = scope.NewHandle<mirror::ClassLoader>(nullptr);
+ std::vector<const DexFile*> class_path;
+
+ if (oat_filename != nullptr) {
+ std::string error_msg;
+ std::unique_ptr<OatFile> oat_file(OatFile::Open(oat_filename,
+ oat_filename,
+ nullptr,
+ nullptr,
+ false,
+ /*low_4gb*/false,
+ nullptr,
+ &error_msg));
+ if (oat_file == nullptr) {
+ fprintf(stderr, "Failed to open oat file from '%s': %s\n", oat_filename, error_msg.c_str());
+ return false;
+ }
+
+ class_loader.Assign(soa.Decode<mirror::ClassLoader>(
+ InstallOatFile(runtime, std::move(oat_file), &class_path)));
+ } else {
+ class_loader.Assign(nullptr); // Boot classloader. Just here for explicit documentation.
+ class_path = runtime->GetClassLinker()->GetBootClassPath();
+ }
+
+ if (!imt_file.empty()) {
+ return DumpImt(runtime, imt_file, class_loader);
+ }
+
+ if (dump_imt_stats) {
+ return DumpImtStats(runtime, class_path, class_loader);
+ }
+
+ LOG(FATAL) << "Should not reach here";
+ UNREACHABLE();
+ }
+
+ private:
+ static bool DumpImt(Runtime* runtime,
+ const std::string& imt_file,
+ Handle<mirror::ClassLoader> h_class_loader)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ std::vector<std::string> lines = ReadCommentedInputFromFile(imt_file);
+ std::unordered_set<std::string> prepared;
+
+ for (const std::string& line : lines) {
+ // A line should be either a class descriptor, in which case we will dump the complete IMT,
+ // or a class descriptor and an interface method, in which case we will lookup the method,
+ // determine its IMT slot, and check the class' IMT.
+ size_t first_space = line.find(' ');
+ if (first_space == std::string::npos) {
+ DumpIMTForClass(runtime, line, h_class_loader, &prepared);
+ } else {
+ DumpIMTForMethod(runtime,
+ line.substr(0, first_space),
+ line.substr(first_space + 1, std::string::npos),
+ h_class_loader,
+ &prepared);
+ }
+ std::cerr << std::endl;
+ }
+
+ return true;
+ }
+
+ static bool DumpImtStats(Runtime* runtime,
+ const std::vector<const DexFile*>& dex_files,
+ Handle<mirror::ClassLoader> h_class_loader)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ size_t without_imt = 0;
+ size_t with_imt = 0;
+ std::map<size_t, size_t> histogram;
+
+ ClassLinker* class_linker = runtime->GetClassLinker();
+ const PointerSize pointer_size = class_linker->GetImagePointerSize();
+ std::unordered_set<std::string> prepared;
+
+ Thread* self = Thread::Current();
+ StackHandleScope<1> scope(self);
+ MutableHandle<mirror::Class> h_klass(scope.NewHandle<mirror::Class>(nullptr));
+
+ for (const DexFile* dex_file : dex_files) {
+ for (uint32_t class_def_index = 0;
+ class_def_index != dex_file->NumClassDefs();
+ ++class_def_index) {
+ const DexFile::ClassDef& class_def = dex_file->GetClassDef(class_def_index);
+ const char* descriptor = dex_file->GetClassDescriptor(class_def);
+ h_klass.Assign(class_linker->FindClass(self, descriptor, h_class_loader));
+ if (h_klass.Get() == nullptr) {
+ std::cerr << "Warning: could not load " << descriptor << std::endl;
+ continue;
+ }
+
+ if (HasNoIMT(runtime, h_klass, pointer_size, &prepared)) {
+ without_imt++;
+ continue;
+ }
+
+ ImTable* im_table = PrepareAndGetImTable(runtime, h_klass, pointer_size, &prepared);
+ if (im_table == nullptr) {
+ // Should not happen, but accept.
+ without_imt++;
+ continue;
+ }
+
+ with_imt++;
+ for (size_t imt_index = 0; imt_index != ImTable::kSize; ++imt_index) {
+ ArtMethod* ptr = im_table->Get(imt_index, pointer_size);
+ if (ptr->IsRuntimeMethod()) {
+ if (ptr->IsImtUnimplementedMethod()) {
+ histogram[0]++;
+ } else {
+ ImtConflictTable* current_table = ptr->GetImtConflictTable(pointer_size);
+ histogram[current_table->NumEntries(pointer_size)]++;
+ }
+ } else {
+ histogram[1]++;
+ }
+ }
+ }
+ }
+
+ std::cerr << "IMT stats:"
+ << std::endl << std::endl;
+
+ std::cerr << " " << with_imt << " classes with IMT."
+ << std::endl << std::endl;
+ std::cerr << " " << without_imt << " classes without IMT (or copy from Object)."
+ << std::endl << std::endl;
+
+ double sum_one = 0;
+ size_t count_one = 0;
+
+ std::cerr << " " << "IMT histogram" << std::endl;
+ for (auto& bucket : histogram) {
+ std::cerr << " " << bucket.first << " " << bucket.second << std::endl;
+ if (bucket.first > 0) {
+ sum_one += bucket.second * bucket.first;
+ count_one += bucket.second;
+ }
+ }
+
+ double count_zero = count_one + histogram[0];
+ std::cerr << " Stats:" << std::endl;
+ std::cerr << " Average depth (including empty): " << (sum_one / count_zero) << std::endl;
+ std::cerr << " Average depth (excluding empty): " << (sum_one / count_one) << std::endl;
+
+ return true;
+ }
+
+ // Return whether the given class has no IMT (or the one shared with java.lang.Object).
+ static bool HasNoIMT(Runtime* runtime,
+ Handle<mirror::Class> klass,
+ const PointerSize pointer_size,
+ std::unordered_set<std::string>* prepared)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ if (klass->IsObjectClass() || !klass->ShouldHaveImt()) {
+ return true;
+ }
+
+ if (klass->GetImt(pointer_size) == nullptr) {
+ PrepareClass(runtime, klass, prepared);
+ }
+
+ mirror::Class* object_class = mirror::Class::GetJavaLangClass()->GetSuperClass();
+ DCHECK(object_class->IsObjectClass());
+
+ bool result = klass->GetImt(pointer_size) == object_class->GetImt(pointer_size);
+
+ if (klass->GetIfTable() == nullptr) {
+ DCHECK(result);
+ }
+
+ return result;
+ }
+
+ static void PrintTable(ImtConflictTable* table, PointerSize pointer_size)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ if (table == nullptr) {
+ std::cerr << " <No IMT?>" << std::endl;
+ return;
+ }
+ size_t table_index = 0;
+ for (;;) {
+ ArtMethod* ptr = table->GetInterfaceMethod(table_index, pointer_size);
+ if (ptr == nullptr) {
+ return;
+ }
+ table_index++;
+ std::cerr << " " << PrettyMethod(ptr, true) << std::endl;
+ }
+ }
+
+ static ImTable* PrepareAndGetImTable(Runtime* runtime,
+ Thread* self,
+ Handle<mirror::ClassLoader> h_loader,
+ const std::string& class_name,
+ const PointerSize pointer_size,
+ mirror::Class** klass_out,
+ std::unordered_set<std::string>* prepared)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ if (class_name.empty()) {
+ return nullptr;
+ }
+
+ std::string descriptor;
+ if (class_name[0] == 'L') {
+ descriptor = class_name;
+ } else {
+ descriptor = DotToDescriptor(class_name.c_str());
+ }
+
+ mirror::Class* klass = runtime->GetClassLinker()->FindClass(self, descriptor.c_str(), h_loader);
+
+ if (klass == nullptr) {
+ self->ClearException();
+ std::cerr << "Did not find " << class_name << std::endl;
+ *klass_out = nullptr;
+ return nullptr;
+ }
+
+ StackHandleScope<1> scope(Thread::Current());
+ Handle<mirror::Class> h_klass = scope.NewHandle<mirror::Class>(klass);
+
+ ImTable* ret = PrepareAndGetImTable(runtime, h_klass, pointer_size, prepared);
+ *klass_out = h_klass.Get();
+ return ret;
+ }
+
+ static ImTable* PrepareAndGetImTable(Runtime* runtime,
+ Handle<mirror::Class> h_klass,
+ const PointerSize pointer_size,
+ std::unordered_set<std::string>* prepared)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ PrepareClass(runtime, h_klass, prepared);
+ return h_klass->GetImt(pointer_size);
+ }
+
+ static void DumpIMTForClass(Runtime* runtime,
+ const std::string& class_name,
+ Handle<mirror::ClassLoader> h_loader,
+ std::unordered_set<std::string>* prepared)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ const PointerSize pointer_size = runtime->GetClassLinker()->GetImagePointerSize();
+ mirror::Class* klass;
+ ImTable* imt = PrepareAndGetImTable(runtime,
+ Thread::Current(),
+ h_loader,
+ class_name,
+ pointer_size,
+ &klass,
+ prepared);
+ if (imt == nullptr) {
+ return;
+ }
+
+ std::cerr << class_name << std::endl << " IMT:" << std::endl;
+ for (size_t index = 0; index < ImTable::kSize; ++index) {
+ std::cerr << " " << index << ":" << std::endl;
+ ArtMethod* ptr = imt->Get(index, pointer_size);
+ if (ptr->IsRuntimeMethod()) {
+ if (ptr->IsImtUnimplementedMethod()) {
+ std::cerr << " <empty>" << std::endl;
+ } else {
+ ImtConflictTable* current_table = ptr->GetImtConflictTable(pointer_size);
+ PrintTable(current_table, pointer_size);
+ }
+ } else {
+ std::cerr << " " << PrettyMethod(ptr, true) << std::endl;
+ }
+ }
+
+ std::cerr << " Interfaces:" << std::endl;
+ // Run through iftable, find methods that slot here, see if they fit.
+ mirror::IfTable* if_table = klass->GetIfTable();
+ if (if_table != nullptr) {
+ for (size_t i = 0, num_interfaces = klass->GetIfTableCount(); i < num_interfaces; ++i) {
+ mirror::Class* iface = if_table->GetInterface(i);
+ std::string iface_name;
+ std::cerr << " " << iface->GetDescriptor(&iface_name) << std::endl;
+
+ for (ArtMethod& iface_method : iface->GetVirtualMethods(pointer_size)) {
+ uint32_t base_hash = ImTable::GetBaseImtHash(&iface_method);
+ uint32_t imt_slot = ImTable::GetImtIndex(&iface_method);
+ std::cerr << " " << PrettyMethod(&iface_method, true) << " slot=" << std::dec
+ << imt_slot << " base_hash=0x" << std::hex << base_hash << std::endl;
+ }
+ }
+ }
+ }
+
+ static void DumpIMTForMethod(Runtime* runtime,
+ const std::string& class_name,
+ const std::string& method,
+ Handle<mirror::ClassLoader> h_loader,
+ std::unordered_set<std::string>* prepared)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ const PointerSize pointer_size = runtime->GetClassLinker()->GetImagePointerSize();
+ mirror::Class* klass;
+ ImTable* imt = PrepareAndGetImTable(runtime,
+ Thread::Current(),
+ h_loader,
+ class_name,
+ pointer_size,
+ &klass,
+ prepared);
+ if (imt == nullptr) {
+ return;
+ }
+
+ std::cerr << class_name << " <" << method << ">" << std::endl;
+ for (size_t index = 0; index < ImTable::kSize; ++index) {
+ ArtMethod* ptr = imt->Get(index, pointer_size);
+ if (ptr->IsRuntimeMethod()) {
+ if (ptr->IsImtUnimplementedMethod()) {
+ continue;
+ }
+
+ ImtConflictTable* current_table = ptr->GetImtConflictTable(pointer_size);
+ if (current_table == nullptr) {
+ continue;
+ }
+
+ size_t table_index = 0;
+ for (;;) {
+ ArtMethod* ptr2 = current_table->GetInterfaceMethod(table_index, pointer_size);
+ if (ptr2 == nullptr) {
+ break;
+ }
+ table_index++;
+
+ std::string p_name = PrettyMethod(ptr2, true);
+ if (StartsWith(p_name, method.c_str())) {
+ std::cerr << " Slot "
+ << index
+ << " ("
+ << current_table->NumEntries(pointer_size)
+ << ")"
+ << std::endl;
+ PrintTable(current_table, pointer_size);
+ return;
+ }
+ }
+ } else {
+ std::string p_name = PrettyMethod(ptr, true);
+ if (StartsWith(p_name, method.c_str())) {
+ std::cerr << " Slot " << index << " (1)" << std::endl;
+ std::cerr << " " << p_name << std::endl;
+ } else {
+ // Run through iftable, find methods that slot here, see if they fit.
+ mirror::IfTable* if_table = klass->GetIfTable();
+ if (if_table != nullptr) {
+ for (size_t i = 0, num_interfaces = klass->GetIfTableCount(); i < num_interfaces; ++i) {
+ mirror::Class* iface = if_table->GetInterface(i);
+ size_t num_methods = iface->NumDeclaredVirtualMethods();
+ if (num_methods > 0) {
+ for (ArtMethod& iface_method : iface->GetMethods(pointer_size)) {
+ if (ImTable::GetImtIndex(&iface_method) == index) {
+ std::string i_name = PrettyMethod(&iface_method, true);
+ if (StartsWith(i_name, method.c_str())) {
+ std::cerr << " Slot " << index << " (1)" << std::endl;
+ std::cerr << " " << p_name << " (" << i_name << ")" << std::endl;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // Read lines from the given stream, dropping comments and empty lines
+ static std::vector<std::string> ReadCommentedInputStream(std::istream& in_stream) {
+ std::vector<std::string> output;
+ while (in_stream.good()) {
+ std::string dot;
+ std::getline(in_stream, dot);
+ if (StartsWith(dot, "#") || dot.empty()) {
+ continue;
+ }
+ output.push_back(dot);
+ }
+ return output;
+ }
+
+ // Read lines from the given file, dropping comments and empty lines.
+ static std::vector<std::string> ReadCommentedInputFromFile(const std::string& input_filename) {
+ std::unique_ptr<std::ifstream> input_file(new std::ifstream(input_filename, std::ifstream::in));
+ if (input_file.get() == nullptr) {
+ LOG(ERROR) << "Failed to open input file " << input_filename;
+ return std::vector<std::string>();
+ }
+ std::vector<std::string> result = ReadCommentedInputStream(*input_file);
+ input_file->close();
+ return result;
+ }
+
+ // Prepare a class, i.e., ensure it has a filled IMT. Will do so recursively for superclasses,
+ // and note in the given set that the work was done.
+ static void PrepareClass(Runtime* runtime,
+ Handle<mirror::Class> h_klass,
+ std::unordered_set<std::string>* done)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ if (!h_klass->ShouldHaveImt()) {
+ return;
+ }
+
+ std::string name;
+ name = h_klass->GetDescriptor(&name);
+
+ if (done->find(name) != done->end()) {
+ return;
+ }
+ done->insert(name);
+
+ if (h_klass->HasSuperClass()) {
+ StackHandleScope<1> h(Thread::Current());
+ PrepareClass(runtime, h.NewHandle<mirror::Class>(h_klass->GetSuperClass()), done);
+ }
+
+ if (!h_klass->IsTemp()) {
+ runtime->GetClassLinker()->FillIMTAndConflictTables(h_klass.Get());
+ }
+ }
+};
+
struct OatdumpArgs : public CmdlineArgs {
protected:
using Base = CmdlineArgs;
@@ -2596,6 +3053,10 @@
app_image_ = option.substr(strlen("--app-image=")).data();
} else if (option.starts_with("--app-oat=")) {
app_oat_ = option.substr(strlen("--app-oat=")).data();
+ } else if (option.starts_with("--dump-imt=")) {
+ imt_dump_ = option.substr(strlen("--dump-imt=")).data();
+ } else if (option == "--dump-imt-stats") {
+ imt_stat_dump_ = true;
} else {
return kParseUnknownArgument;
}
@@ -2692,6 +3153,16 @@
" --addr2instr=<address>: output matching method disassembled code from relative\n"
" address (e.g. PC from crash dump)\n"
" Example: --addr2instr=0x00001a3b\n"
+ "\n"
+ " --dump-imt=<file.txt>: output IMT collisions (if any) for the given receiver\n"
+ " types and interface methods in the given file. The file\n"
+ " is read line-wise, where each line should either be a class\n"
+ " name or descriptor, or a class name/descriptor and a prefix\n"
+ " of a complete method name (separated by a whitespace).\n"
+ " Example: --dump-imt=imt.txt\n"
+ "\n"
+ " --dump-imt-stats: output IMT statistics for the given boot image\n"
+ " Example: --dump-imt-stats"
"\n";
return usage;
@@ -2703,6 +3174,7 @@
const char* method_filter_ = "";
const char* image_location_ = nullptr;
std::string elf_filename_prefix_;
+ std::string imt_dump_;
bool dump_vmap_ = true;
bool dump_code_info_stack_maps_ = false;
bool disassemble_code_ = true;
@@ -2711,6 +3183,7 @@
bool list_classes_ = false;
bool list_methods_ = false;
bool dump_header_only_ = false;
+ bool imt_stat_dump_ = false;
uint32_t addr2instr_ = 0;
const char* export_dex_location_ = nullptr;
const char* app_image_ = nullptr;
@@ -2739,7 +3212,9 @@
args_->app_oat_,
args_->addr2instr_));
- return (args_->boot_image_location_ != nullptr || args_->image_location_ != nullptr) &&
+ return (args_->boot_image_location_ != nullptr ||
+ args_->image_location_ != nullptr ||
+ !args_->imt_dump_.empty()) &&
!args_->symbolize_;
}
@@ -2767,6 +3242,13 @@
virtual bool ExecuteWithRuntime(Runtime* runtime) {
CHECK(args_ != nullptr);
+ if (!args_->imt_dump_.empty() || args_->imt_stat_dump_) {
+ return IMTDumper::Dump(runtime,
+ args_->imt_dump_,
+ args_->imt_stat_dump_,
+ args_->oat_filename_);
+ }
+
if (args_->oat_filename_ != nullptr) {
return DumpOat(runtime,
args_->oat_filename_,
diff --git a/patchoat/patchoat.cc b/patchoat/patchoat.cc
index 1af3660..d58f38c 100644
--- a/patchoat/patchoat.cc
+++ b/patchoat/patchoat.cc
@@ -46,7 +46,7 @@
#include "offsets.h"
#include "os.h"
#include "runtime.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
#include "thread.h"
#include "utils.h"
diff --git a/runtime/Android.bp b/runtime/Android.bp
index fd9b5b9..31f2490 100644
--- a/runtime/Android.bp
+++ b/runtime/Android.bp
@@ -126,6 +126,8 @@
"mirror/executable.cc",
"mirror/field.cc",
"mirror/method.cc",
+ "mirror/method_handle_impl.cc",
+ "mirror/method_type.cc",
"mirror/object.cc",
"mirror/reference.cc",
"mirror/stack_trace_element.cc",
@@ -546,6 +548,7 @@
"mem_map_test.cc",
"memory_region_test.cc",
"mirror/dex_cache_test.cc",
+ "mirror/method_type_test.cc",
"mirror/object_test.cc",
"monitor_pool_test.cc",
"monitor_test.cc",
diff --git a/runtime/arch/arm/quick_entrypoints_arm.S b/runtime/arch/arm/quick_entrypoints_arm.S
index 5d53062..cdb4c25 100644
--- a/runtime/arch/arm/quick_entrypoints_arm.S
+++ b/runtime/arch/arm/quick_entrypoints_arm.S
@@ -1710,7 +1710,11 @@
.cfi_rel_offset lr, 12
ldr r3, [r0, #MIRROR_STRING_COUNT_OFFSET]
add r0, #MIRROR_STRING_VALUE_OFFSET
-
+#if (STRING_COMPRESSION_FEATURE)
+ /* r4 count (with flag) and r3 holds actual length */
+ mov r4, r3
+ bic r3, #2147483648
+#endif
/* Clamp start to [0..count] */
cmp r2, #0
it lt
@@ -1723,6 +1727,10 @@
mov r12, r0
/* Build pointer to start of data to compare and pre-bias */
+#if (STRING_COMPRESSION_FEATURE)
+ cmp r4, #0
+ blt .Lstring_indexof_compressed
+#endif
add r0, r0, r2, lsl #1
sub r0, #2
@@ -1734,6 +1742,7 @@
* r0: start of data to test
* r1: char to compare
* r2: iteration count
+ * r4: compression style (used temporarily)
* r12: original start of string data
* r3, r4, r10, r11 available for loading string data
*/
@@ -1791,6 +1800,22 @@
sub r0, r12
asr r0, r0, #1
pop {r4, r10-r11, pc}
+#if (STRING_COMPRESSION_FEATURE)
+.Lstring_indexof_compressed:
+ add r0, r0, r2
+ sub r0, #1
+ sub r2, r3, r2
+.Lstring_indexof_compressed_loop:
+ subs r2, #1
+ blt .Lindexof_nomatch
+ ldrb r3, [r0, #1]!
+ cmp r3, r1
+ beq .Lstring_indexof_compressed_matched
+ b .Lstring_indexof_compressed_loop
+.Lstring_indexof_compressed_matched:
+ sub r0, r12
+ pop {r4, r10-r11, pc}
+#endif
END art_quick_indexof
/* Assembly routines used to handle ABI differences. */
diff --git a/runtime/arch/arm64/quick_entrypoints_arm64.S b/runtime/arch/arm64/quick_entrypoints_arm64.S
index eee949d..04a3cc6 100644
--- a/runtime/arch/arm64/quick_entrypoints_arm64.S
+++ b/runtime/arch/arm64/quick_entrypoints_arm64.S
@@ -2378,7 +2378,11 @@
ENTRY art_quick_indexof
ldr w3, [x0, #MIRROR_STRING_COUNT_OFFSET]
add x0, x0, #MIRROR_STRING_VALUE_OFFSET
-
+#if (STRING_COMPRESSION_FEATURE)
+ /* w4 holds count (with flag) and w3 holds actual length */
+ mov w4, w3
+ and w3, w3, #2147483647
+#endif
/* Clamp start to [0..count] */
cmp w2, #0
csel w2, wzr, w2, lt
@@ -2388,10 +2392,12 @@
/* Save a copy to compute result */
mov x5, x0
+#if (STRING_COMPRESSION_FEATURE)
+ tbnz w4, #31, .Lstring_indexof_compressed
+#endif
/* Build pointer to start of data to compare and pre-bias */
add x0, x0, x2, lsl #1
sub x0, x0, #2
-
/* Compute iteration count */
sub w2, w3, w2
@@ -2456,6 +2462,26 @@
sub x0, x0, x5
asr x0, x0, #1
ret
+#if (STRING_COMPRESSION_FEATURE)
+ /*
+ * Comparing compressed string character-per-character with
+ * input character
+ */
+.Lstring_indexof_compressed:
+ add x0, x0, x2
+ sub x0, x0, #1
+ sub w2, w3, w2
+.Lstring_indexof_compressed_loop:
+ subs w2, w2, #1
+ b.lt .Lindexof_nomatch
+ ldrb w6, [x0, #1]!
+ cmp w6, w1
+ b.eq .Lstring_indexof_compressed_matched
+ b .Lstring_indexof_compressed_loop
+.Lstring_indexof_compressed_matched:
+ sub x0, x0, x5
+ ret
+#endif
END art_quick_indexof
/*
diff --git a/runtime/arch/instruction_set_features_test.cc b/runtime/arch/instruction_set_features_test.cc
index 7bbc709..0b8e531 100644
--- a/runtime/arch/instruction_set_features_test.cc
+++ b/runtime/arch/instruction_set_features_test.cc
@@ -19,7 +19,7 @@
#include <gtest/gtest.h>
#ifdef ART_TARGET_ANDROID
-#include "cutils/properties.h"
+#include "android-base/properties.h"
#endif
#include "base/logging.h"
@@ -40,8 +40,8 @@
// Read the variant property.
std::string key = StringPrintf("dalvik.vm.isa.%s.variant", GetInstructionSetString(kRuntimeISA));
- char dex2oat_isa_variant[PROPERTY_VALUE_MAX];
- if (property_get(key.c_str(), dex2oat_isa_variant, nullptr) > 0) {
+ std::string dex2oat_isa_variant = android::base::GetProperty(key, "");
+ if (!dex2oat_isa_variant.empty()) {
// Use features from property to build InstructionSetFeatures and check against build's
// features.
std::string error_msg;
@@ -68,13 +68,13 @@
// Read the variant property.
std::string variant_key = StringPrintf("dalvik.vm.isa.%s.variant",
GetInstructionSetString(kRuntimeISA));
- char dex2oat_isa_variant[PROPERTY_VALUE_MAX];
- if (property_get(variant_key.c_str(), dex2oat_isa_variant, nullptr) > 0) {
+ std::string dex2oat_isa_variant = android::base::GetProperty(variant_key, "");
+ if (!dex2oat_isa_variant.empty()) {
// Read the features property.
std::string features_key = StringPrintf("dalvik.vm.isa.%s.features",
GetInstructionSetString(kRuntimeISA));
- char dex2oat_isa_features[PROPERTY_VALUE_MAX];
- if (property_get(features_key.c_str(), dex2oat_isa_features, nullptr) > 0) {
+ std::string dex2oat_isa_features = android::base::GetProperty(features_key, "");
+ if (!dex2oat_isa_features.empty()) {
// Use features from property to build InstructionSetFeatures and check against build's
// features.
std::string error_msg;
diff --git a/runtime/arch/stub_test.cc b/runtime/arch/stub_test.cc
index 3424e3c..5e39f42 100644
--- a/runtime/arch/stub_test.cc
+++ b/runtime/arch/stub_test.cc
@@ -26,7 +26,7 @@
#include "linear_alloc.h"
#include "mirror/class-inl.h"
#include "mirror/string-inl.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
namespace art {
@@ -1796,7 +1796,7 @@
ScopedObjectAccess soa(self);
StackHandleScope<3> hs(self);
- Handle<mirror::Object> obj(hs.NewHandle(soa.Decode<mirror::Object*>(o)));
+ Handle<mirror::Object> obj(hs.NewHandle(soa.Decode<mirror::Object>(o)));
Handle<mirror::Class> c(hs.NewHandle(obj->GetClass()));
// Need a method as a referrer
ArtMethod* m = c->GetDirectMethod(0, kRuntimePointerSize);
@@ -1995,11 +1995,11 @@
jobject jarray_list = env->NewObject(arraylist_jclass, arraylist_constructor);
ASSERT_NE(nullptr, jarray_list);
- Handle<mirror::Object> array_list(hs.NewHandle(soa.Decode<mirror::Object*>(jarray_list)));
+ Handle<mirror::Object> array_list(hs.NewHandle(soa.Decode<mirror::Object>(jarray_list)));
jobject jobj = env->NewObject(obj_jclass, obj_constructor);
ASSERT_NE(nullptr, jobj);
- Handle<mirror::Object> obj(hs.NewHandle(soa.Decode<mirror::Object*>(jobj)));
+ Handle<mirror::Object> obj(hs.NewHandle(soa.Decode<mirror::Object>(jobj)));
// Invocation tests.
diff --git a/runtime/arch/x86/quick_entrypoints_x86.S b/runtime/arch/x86/quick_entrypoints_x86.S
index 879d496..7bb59ef 100644
--- a/runtime/arch/x86/quick_entrypoints_x86.S
+++ b/runtime/arch/x86/quick_entrypoints_x86.S
@@ -1986,11 +1986,70 @@
mov MIRROR_STRING_COUNT_OFFSET(%ecx), %ebx
lea MIRROR_STRING_VALUE_OFFSET(%eax), %esi
lea MIRROR_STRING_VALUE_OFFSET(%ecx), %edi
+#if (STRING_COMPRESSION_FEATURE)
+ /* Differ cases */
+ cmpl LITERAL(0), %edx
+ jl .Lstring_compareto_this_is_compressed
+ cmpl LITERAL(0), %ebx
+ jl .Lstring_compareto_that_is_compressed
+ jmp .Lstring_compareto_both_not_compressed
+.Lstring_compareto_this_is_compressed:
+ andl LITERAL(0x7FFFFFFF), %edx
+ cmpl LITERAL(0), %ebx
+ jl .Lstring_compareto_both_compressed
+ /* If (this->IsCompressed() && that->IsCompressed() == false) */
+ mov %edx, %eax
+ subl %ebx, %eax
+ mov %edx, %ecx
+ cmovg %ebx, %ecx
+ /* Going into loop to compare each character */
+ jecxz .Lstring_compareto_keep_length // check loop counter (if 0, don't compare)
+.Lstring_compareto_loop_comparison_this_compressed:
+ movzbl (%esi), %edx // move *(this_cur_char) byte to long
+ movzwl (%edi), %ebx // move *(that_cur_char) word to long
+ addl LITERAL(1), %esi // ++this_cur_char (8-bit)
+ addl LITERAL(2), %edi // ++that_cur_char (16-bit)
+ subl %ebx, %edx
+ loope .Lstring_compareto_loop_comparison_this_compressed
+ cmovne %edx, %eax // return eax = *(this_cur_char) - *(that_cur_char)
+ jmp .Lstring_compareto_return
+.Lstring_compareto_that_is_compressed:
+ andl LITERAL(0x7FFFFFFF), %ebx
+ mov %edx, %eax
+ subl %ebx, %eax
+ mov %edx, %ecx
+ cmovg %ebx, %ecx
+ /* If (this->IsCompressed() == false && that->IsCompressed()) */
+ jecxz .Lstring_compareto_keep_length // check loop counter, if 0, don't compare
+.Lstring_compareto_loop_comparison_that_compressed:
+ movzwl (%esi), %edx // move *(this_cur_char) word to long
+ movzbl (%edi), %ebx // move *(that_cur_char) byte to long
+ addl LITERAL(2), %esi // ++this_cur_char (16-bit)
+ addl LITERAL(1), %edi // ++that_cur_char (8-bit)
+ subl %ebx, %edx
+ loope .Lstring_compareto_loop_comparison_that_compressed
+ cmovne %edx, %eax
+ jmp .Lstring_compareto_return // return eax = *(this_cur_char) - *(that_cur_char)
+.Lstring_compareto_both_compressed:
+ andl LITERAL(0x7FFFFFFF), %ebx
/* Calculate min length and count diff */
- mov %edx, %ecx
- mov %edx, %eax
- subl %ebx, %eax
- cmovg %ebx, %ecx
+ mov %edx, %ecx
+ mov %edx, %eax
+ subl %ebx, %eax
+ cmovg %ebx, %ecx
+ jecxz .Lstring_compareto_keep_length
+ repe cmpsb
+ je .Lstring_compareto_keep_length
+ movzbl -1(%esi), %eax // get last compared char from this string (8-bit)
+ movzbl -1(%edi), %ecx // get last compared char from comp string (8-bit)
+ jmp .Lstring_compareto_count_difference
+#endif // STRING_COMPRESSION_FEATURE
+.Lstring_compareto_both_not_compressed:
+ /* Calculate min length and count diff */
+ mov %edx, %ecx
+ mov %edx, %eax
+ subl %ebx, %eax
+ cmovg %ebx, %ecx
/*
* At this point we have:
* eax: value to return if first part of strings are equal
@@ -1998,18 +2057,15 @@
* esi: pointer to this string data
* edi: pointer to comp string data
*/
- jecxz .Lkeep_length
- repe cmpsw // find nonmatching chars in [%esi] and [%edi], up to length %ecx
- jne .Lnot_equal
-.Lkeep_length:
- POP edi // pop callee save reg
- POP esi // pop callee save reg
- ret
- .balign 16
-.Lnot_equal:
- movzwl -2(%esi), %eax // get last compared char from this string
- movzwl -2(%edi), %ecx // get last compared char from comp string
- subl %ecx, %eax // return the difference
+ jecxz .Lstring_compareto_keep_length
+ repe cmpsw // find nonmatching chars in [%esi] and [%edi], up to length %ecx
+ je .Lstring_compareto_keep_length
+ movzwl -2(%esi), %eax // get last compared char from this string (16-bit)
+ movzwl -2(%edi), %ecx // get last compared char from comp string (16-bit)
+.Lstring_compareto_count_difference:
+ subl %ecx, %eax
+.Lstring_compareto_keep_length:
+.Lstring_compareto_return:
POP edi // pop callee save reg
POP esi // pop callee save reg
ret
diff --git a/runtime/arch/x86_64/quick_entrypoints_x86_64.S b/runtime/arch/x86_64/quick_entrypoints_x86_64.S
index a11e402..54e52e5 100644
--- a/runtime/arch/x86_64/quick_entrypoints_x86_64.S
+++ b/runtime/arch/x86_64/quick_entrypoints_x86_64.S
@@ -2100,11 +2100,70 @@
/* Build pointers to the start of string data */
leal MIRROR_STRING_VALUE_OFFSET(%edi), %edi
leal MIRROR_STRING_VALUE_OFFSET(%esi), %esi
+#if (STRING_COMPRESSION_FEATURE)
+ /* Differ cases */
+ cmpl LITERAL(0), %r8d
+ jl .Lstring_compareto_this_is_compressed
+ cmpl LITERAL(0), %r9d
+ jl .Lstring_compareto_that_is_compressed
+ jmp .Lstring_compareto_both_not_compressed
+.Lstring_compareto_this_is_compressed:
+ andl LITERAL(0x7FFFFFFF), %r8d
+ cmpl LITERAL(0), %r9d
+ jl .Lstring_compareto_both_compressed
+ /* Comparison this (8-bit) and that (16-bit) */
+ mov %r8d, %eax
+ subl %r9d, %eax
+ mov %r8d, %ecx
+ cmovg %r9d, %ecx
+ /* Going into loop to compare each character */
+ jecxz .Lstring_compareto_keep_length // check loop counter (if 0 then stop)
+.Lstring_compareto_loop_comparison_this_compressed:
+ movzbl (%edi), %r8d // move *(this_cur_char) byte to long
+ movzwl (%esi), %r9d // move *(that_cur_char) word to long
+ addl LITERAL(1), %edi // ++this_cur_char (8-bit)
+ addl LITERAL(2), %esi // ++that_cur_char (16-bit)
+ subl %r9d, %r8d
+ loope .Lstring_compareto_loop_comparison_this_compressed
+ cmovne %r8d, %eax // return eax = *(this_cur_char) - *(that_cur_char)
+ ret
+.Lstring_compareto_that_is_compressed:
+ andl LITERAL(0x7FFFFFFF), %r9d
+ movl %r8d, %eax
+ subl %r9d, %eax
+ mov %r8d, %ecx
+ cmovg %r9d, %ecx
+ /* Comparison this (8-bit) and that (16-bit) */
+ jecxz .Lstring_compareto_keep_length // check loop counter (if 0, don't compare)
+.Lstring_compareto_loop_comparison_that_compressed:
+ movzwl (%edi), %r8d // move *(this_cur_char) word to long
+ movzbl (%esi), %r9d // move *(that_cur_chat) byte to long
+ addl LITERAL(2), %edi // ++this_cur_char (16-bit)
+ addl LITERAL(1), %esi // ++that_cur_char (8-bit)
+ subl %r9d, %r8d
+ loope .Lstring_compareto_loop_comparison_that_compressed
+ cmovne %r8d, %eax // return eax = *(this_cur_char) - *(that_cur_char)
+ ret
+.Lstring_compareto_both_compressed:
+ andl LITERAL(0x7FFFFFFF), %r9d
/* Calculate min length and count diff */
- movl %r8d, %ecx
- movl %r8d, %eax
- subl %r9d, %eax
- cmovg %r9d, %ecx
+ movl %r8d, %ecx
+ movl %r8d, %eax
+ subl %r9d, %eax
+ cmovg %r9d, %ecx
+ jecxz .Lstring_compareto_keep_length
+ repe cmpsb
+ je .Lstring_compareto_keep_length
+ movzbl -1(%edi), %eax // get last compared char from this string (8-bit)
+ movzbl -1(%esi), %ecx // get last compared char from comp string (8-bit)
+ jmp .Lstring_compareto_count_difference
+#endif // STRING_COMPRESSION_FEATURE
+.Lstring_compareto_both_not_compressed:
+ /* Calculate min length and count diff */
+ movl %r8d, %ecx
+ movl %r8d, %eax
+ subl %r9d, %eax
+ cmovg %r9d, %ecx
/*
* At this point we have:
* eax: value to return if first part of strings are equal
@@ -2112,16 +2171,14 @@
* esi: pointer to comp string data
* edi: pointer to this string data
*/
- jecxz .Lkeep_length
- repe cmpsw // find nonmatching chars in [%esi] and [%edi], up to length %ecx
- jne .Lnot_equal
-.Lkeep_length:
- ret
- .balign 16
-.Lnot_equal:
- movzwl -2(%edi), %eax // get last compared char from this string
- movzwl -2(%esi), %ecx // get last compared char from comp string
+ jecxz .Lstring_compareto_keep_length
+ repe cmpsw // find nonmatching chars in [%esi] and [%edi], up to length %ecx
+ je .Lstring_compareto_keep_length
+ movzwl -2(%edi), %eax // get last compared char from this string (16-bit)
+ movzwl -2(%esi), %ecx // get last compared char from comp string (16-bit)
+.Lstring_compareto_count_difference:
subl %ecx, %eax // return the difference
+.Lstring_compareto_keep_length:
ret
END_FUNCTION art_quick_string_compareto
diff --git a/runtime/art_field-inl.h b/runtime/art_field-inl.h
index ef75f94..ca96169 100644
--- a/runtime/art_field-inl.h
+++ b/runtime/art_field-inl.h
@@ -28,7 +28,7 @@
#include "mirror/object-inl.h"
#include "primitive.h"
#include "thread-inl.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
#include "well_known_classes.h"
namespace art {
diff --git a/runtime/art_field.cc b/runtime/art_field.cc
index ea5078e..3b4db0b 100644
--- a/runtime/art_field.cc
+++ b/runtime/art_field.cc
@@ -24,7 +24,7 @@
#include "mirror/object-inl.h"
#include "mirror/object_array-inl.h"
#include "runtime.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
#include "utils.h"
#include "well_known_classes.h"
diff --git a/runtime/art_method-inl.h b/runtime/art_method-inl.h
index 73cce5e..73c6cf1 100644
--- a/runtime/art_method-inl.h
+++ b/runtime/art_method-inl.h
@@ -36,7 +36,7 @@
#include "quick/quick_method_frame_info.h"
#include "read_barrier-inl.h"
#include "runtime-inl.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
#include "thread-inl.h"
#include "utils.h"
diff --git a/runtime/art_method.cc b/runtime/art_method.cc
index 193bea1..c97c328 100644
--- a/runtime/art_method.cc
+++ b/runtime/art_method.cc
@@ -40,7 +40,7 @@
#include "mirror/object-inl.h"
#include "mirror/string.h"
#include "oat_file-inl.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
#include "well_known_classes.h"
namespace art {
@@ -52,7 +52,7 @@
ArtMethod* ArtMethod::FromReflectedMethod(const ScopedObjectAccessAlreadyRunnable& soa,
jobject jlr_method) {
- auto* executable = soa.Decode<mirror::Executable*>(jlr_method);
+ ObjPtr<mirror::Executable> executable = soa.Decode<mirror::Executable>(jlr_method);
DCHECK(executable != nullptr);
return executable->GetArtMethod();
}
@@ -350,7 +350,7 @@
ScopedObjectAccess soa(self);
StackHandleScope<1> shs(self);
- mirror::Class* annotation = soa.Decode<mirror::Class*>(klass);
+ ObjPtr<mirror::Class> annotation = soa.Decode<mirror::Class>(klass);
DCHECK(annotation->IsAnnotation());
Handle<mirror::Class> annotation_handle(shs.NewHandle(annotation));
diff --git a/runtime/art_method.h b/runtime/art_method.h
index 3d2db69..7a8f479 100644
--- a/runtime/art_method.h
+++ b/runtime/art_method.h
@@ -137,7 +137,52 @@
return (GetAccessFlags() & kAccFinal) != 0;
}
+ bool IsIntrinsic() {
+ return (GetAccessFlags() & kAccIntrinsic) != 0;
+ }
+
+ void SetIntrinsic(uint32_t intrinsic) {
+ DCHECK(IsUint<8>(intrinsic));
+ uint32_t new_value = (GetAccessFlags() & kAccFlagsNotUsedByIntrinsic) |
+ kAccIntrinsic |
+ (intrinsic << POPCOUNT(kAccFlagsNotUsedByIntrinsic));
+ if (kIsDebugBuild) {
+ uint32_t java_flags = (GetAccessFlags() & kAccJavaFlagsMask);
+ bool is_constructor = IsConstructor();
+ bool is_synchronized = IsSynchronized();
+ bool skip_access_checks = SkipAccessChecks();
+ bool is_fast_native = IsFastNative();
+ bool is_copied = IsCopied();
+ bool is_miranda = IsMiranda();
+ bool is_default = IsDefault();
+ bool is_default_conflict = IsDefaultConflicting();
+ bool is_compilable = IsCompilable();
+ bool must_count_locks = MustCountLocks();
+ SetAccessFlags(new_value);
+ DCHECK_EQ(java_flags, (GetAccessFlags() & kAccJavaFlagsMask));
+ DCHECK_EQ(is_constructor, IsConstructor());
+ DCHECK_EQ(is_synchronized, IsSynchronized());
+ DCHECK_EQ(skip_access_checks, SkipAccessChecks());
+ DCHECK_EQ(is_fast_native, IsFastNative());
+ DCHECK_EQ(is_copied, IsCopied());
+ DCHECK_EQ(is_miranda, IsMiranda());
+ DCHECK_EQ(is_default, IsDefault());
+ DCHECK_EQ(is_default_conflict, IsDefaultConflicting());
+ DCHECK_EQ(is_compilable, IsCompilable());
+ DCHECK_EQ(must_count_locks, MustCountLocks());
+ } else {
+ SetAccessFlags(new_value);
+ }
+ }
+
+ uint32_t GetIntrinsic() {
+ DCHECK(IsIntrinsic());
+ return (GetAccessFlags() >> POPCOUNT(kAccFlagsNotUsedByIntrinsic)) & kAccMaxIntrinsic;
+ }
+
bool IsCopied() {
+ static_assert((kAccCopied & kAccFlagsNotUsedByIntrinsic) == kAccCopied,
+ "kAccCopied conflicts with intrinsic modifier");
const bool copied = (GetAccessFlags() & kAccCopied) != 0;
// (IsMiranda() || IsDefaultConflicting()) implies copied
DCHECK(!(IsMiranda() || IsDefaultConflicting()) || copied)
@@ -146,6 +191,8 @@
}
bool IsMiranda() {
+ static_assert((kAccMiranda & kAccFlagsNotUsedByIntrinsic) == kAccMiranda,
+ "kAccMiranda conflicts with intrinsic modifier");
return (GetAccessFlags() & kAccMiranda) != 0;
}
@@ -156,6 +203,9 @@
}
bool IsCompilable() {
+ if (IsIntrinsic()) {
+ return true;
+ }
return (GetAccessFlags() & kAccCompileDontBother) == 0;
}
@@ -163,11 +213,16 @@
// multiple default methods. It cannot be invoked, throwing an IncompatibleClassChangeError if one
// attempts to do so.
bool IsDefaultConflicting() {
+ if (IsIntrinsic()) {
+ return false;
+ }
return (GetAccessFlags() & kAccDefaultConflict) != 0u;
}
// This is set by the class linker.
bool IsDefault() {
+ static_assert((kAccDefault & kAccFlagsNotUsedByIntrinsic) == kAccDefault,
+ "kAccDefault conflicts with intrinsic modifier");
return (GetAccessFlags() & kAccDefault) != 0;
}
@@ -204,6 +259,9 @@
// Should this method be run in the interpreter and count locks (e.g., failed structured-
// locking verification)?
bool MustCountLocks() {
+ if (IsIntrinsic()) {
+ return false;
+ }
return (GetAccessFlags() & kAccMustCountLocks) != 0;
}
diff --git a/runtime/asm_support.h b/runtime/asm_support.h
index b8f7272..567791e 100644
--- a/runtime/asm_support.h
+++ b/runtime/asm_support.h
@@ -240,7 +240,9 @@
#define MIRROR_STRING_VALUE_OFFSET (8 + MIRROR_OBJECT_HEADER_SIZE)
ADD_TEST_EQ(MIRROR_STRING_VALUE_OFFSET, art::mirror::String::ValueOffset().Int32Value())
-
+// String compression feature.
+#define STRING_COMPRESSION_FEATURE 0
+ADD_TEST_EQ(STRING_COMPRESSION_FEATURE, art::mirror::kUseStringCompression);
#if defined(__cplusplus)
} // End of CheckAsmSupportOffsets.
diff --git a/runtime/base/mutex.cc b/runtime/base/mutex.cc
index 9d56954..1183dea 100644
--- a/runtime/base/mutex.cc
+++ b/runtime/base/mutex.cc
@@ -26,7 +26,7 @@
#include "base/value_object.h"
#include "mutex-inl.h"
#include "runtime.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
#include "thread-inl.h"
namespace art {
diff --git a/runtime/base/mutex.h b/runtime/base/mutex.h
index 8af9fa5..91e31d8 100644
--- a/runtime/base/mutex.h
+++ b/runtime/base/mutex.h
@@ -78,7 +78,6 @@
kAllocSpaceLock,
kBumpPointerSpaceBlockLock,
kArenaPoolLock,
- kDexFileMethodInlinerLock,
kDexFileToMethodInlinerMapLock,
kInternTableLock,
kOatFileSecondaryLookupLock,
diff --git a/runtime/check_jni.cc b/runtime/check_jni.cc
index a980535..9f07702 100644
--- a/runtime/check_jni.cc
+++ b/runtime/check_jni.cc
@@ -36,7 +36,7 @@
#include "mirror/string-inl.h"
#include "mirror/throwable.h"
#include "runtime.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
#include "thread.h"
#include "well_known_classes.h"
@@ -269,12 +269,12 @@
*/
bool CheckInstanceFieldID(ScopedObjectAccess& soa, jobject java_object, jfieldID fid)
REQUIRES_SHARED(Locks::mutator_lock_) {
- mirror::Object* o = soa.Decode<mirror::Object*>(java_object);
+ ObjPtr<mirror::Object> o = soa.Decode<mirror::Object>(java_object);
if (o == nullptr) {
AbortF("field operation on NULL object: %p", java_object);
return false;
}
- if (!Runtime::Current()->GetHeap()->IsValidObjectAddress(o)) {
+ if (!Runtime::Current()->GetHeap()->IsValidObjectAddress(o.Decode())) {
Runtime::Current()->GetHeap()->DumpSpaces(LOG_STREAM(ERROR));
AbortF("field operation on invalid %s: %p",
ToStr<IndirectRefKind>(GetIndirectRefKind(java_object)).c_str(),
@@ -333,15 +333,15 @@
return false;
}
if (invoke != kVirtual) {
- mirror::Class* c = soa.Decode<mirror::Class*>(jc);
- if (!m->GetDeclaringClass()->IsAssignableFrom(c)) {
+ ObjPtr<mirror::Class> c = soa.Decode<mirror::Class>(jc);
+ if (!m->GetDeclaringClass()->IsAssignableFrom(c.Decode())) {
AbortF("can't call %s %s with class %s", invoke == kStatic ? "static" : "nonvirtual",
PrettyMethod(m).c_str(), PrettyClass(c).c_str());
return false;
}
}
if (invoke != kStatic) {
- mirror::Object* o = soa.Decode<mirror::Object*>(jobj);
+ ObjPtr<mirror::Object> o = soa.Decode<mirror::Object>(jobj);
if (o == nullptr) {
AbortF("can't call %s on null object", PrettyMethod(m).c_str());
return false;
@@ -360,12 +360,12 @@
*/
bool CheckStaticFieldID(ScopedObjectAccess& soa, jclass java_class, jfieldID fid)
REQUIRES_SHARED(Locks::mutator_lock_) {
- mirror::Class* c = soa.Decode<mirror::Class*>(java_class);
+ ObjPtr<mirror::Class> c = soa.Decode<mirror::Class>(java_class);
ArtField* f = CheckFieldID(soa, fid);
if (f == nullptr) {
return false;
}
- if (f->GetDeclaringClass() != c) {
+ if (c != f->GetDeclaringClass()) {
AbortF("static jfieldID %p not valid for class %s", fid, PrettyClass(c).c_str());
return false;
}
@@ -387,8 +387,8 @@
if (m == nullptr) {
return false;
}
- mirror::Class* c = soa.Decode<mirror::Class*>(java_class);
- if (!m->GetDeclaringClass()->IsAssignableFrom(c)) {
+ ObjPtr<mirror::Class> c = soa.Decode<mirror::Class>(java_class);
+ if (!m->GetDeclaringClass()->IsAssignableFrom(c.Decode())) {
AbortF("can't call static %s on class %s", PrettyMethod(m).c_str(), PrettyClass(c).c_str());
return false;
}
@@ -408,7 +408,7 @@
if (m == nullptr) {
return false;
}
- mirror::Object* o = soa.Decode<mirror::Object*>(java_object);
+ ObjPtr<mirror::Object> o = soa.Decode<mirror::Object>(java_object);
if (o == nullptr) {
AbortF("can't call %s on null object", PrettyMethod(m).c_str());
return false;
@@ -557,14 +557,14 @@
bool CheckReflectedMethod(ScopedObjectAccess& soa, jobject jmethod)
REQUIRES_SHARED(Locks::mutator_lock_) {
- mirror::Object* method = soa.Decode<mirror::Object*>(jmethod);
+ ObjPtr<mirror::Object> method = soa.Decode<mirror::Object>(jmethod);
if (method == nullptr) {
AbortF("expected non-null method");
return false;
}
mirror::Class* c = method->GetClass();
- if (soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_reflect_Method) != c &&
- soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_reflect_Constructor) != c) {
+ if (soa.Decode<mirror::Class>(WellKnownClasses::java_lang_reflect_Method) != c &&
+ soa.Decode<mirror::Class>(WellKnownClasses::java_lang_reflect_Constructor) != c) {
AbortF("expected java.lang.reflect.Method or "
"java.lang.reflect.Constructor but got object of type %s: %p",
PrettyTypeOf(method).c_str(), jmethod);
@@ -589,13 +589,13 @@
bool CheckReflectedField(ScopedObjectAccess& soa, jobject jfield)
REQUIRES_SHARED(Locks::mutator_lock_) {
- mirror::Object* field = soa.Decode<mirror::Object*>(jfield);
+ ObjPtr<mirror::Object> field = soa.Decode<mirror::Object>(jfield);
if (field == nullptr) {
AbortF("expected non-null java.lang.reflect.Field");
return false;
}
mirror::Class* c = field->GetClass();
- if (soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_reflect_Field) != c) {
+ if (soa.Decode<mirror::Class>(WellKnownClasses::java_lang_reflect_Field) != c) {
AbortF("expected java.lang.reflect.Field but got object of type %s: %p",
PrettyTypeOf(field).c_str(), jfield);
return false;
@@ -605,10 +605,10 @@
bool CheckThrowable(ScopedObjectAccess& soa, jthrowable jobj)
REQUIRES_SHARED(Locks::mutator_lock_) {
- mirror::Object* obj = soa.Decode<mirror::Object*>(jobj);
+ ObjPtr<mirror::Object> obj = soa.Decode<mirror::Object>(jobj);
if (!obj->GetClass()->IsThrowableClass()) {
AbortF("expected java.lang.Throwable but got object of type "
- "%s: %p", PrettyTypeOf(obj).c_str(), obj);
+ "%s: %p", PrettyTypeOf(obj).c_str(), obj.Decode());
return false;
}
return true;
@@ -616,10 +616,10 @@
bool CheckThrowableClass(ScopedObjectAccess& soa, jclass jc)
REQUIRES_SHARED(Locks::mutator_lock_) {
- mirror::Class* c = soa.Decode<mirror::Class*>(jc);
+ ObjPtr<mirror::Class> c = soa.Decode<mirror::Class>(jc);
if (!c->IsThrowableClass()) {
AbortF("expected java.lang.Throwable class but got object of "
- "type %s: %p", PrettyDescriptor(c).c_str(), c);
+ "type %s: %p", PrettyDescriptor(c).c_str(), c.Decode());
return false;
}
return true;
@@ -647,9 +647,9 @@
bool CheckInstantiableNonArray(ScopedObjectAccess& soa, jclass jc)
REQUIRES_SHARED(Locks::mutator_lock_) {
- mirror::Class* c = soa.Decode<mirror::Class*>(jc);
+ ObjPtr<mirror::Class> c = soa.Decode<mirror::Class>(jc);
if (!c->IsInstantiableNonArray()) {
- AbortF("can't make objects of type %s: %p", PrettyDescriptor(c).c_str(), c);
+ AbortF("can't make objects of type %s: %p", PrettyDescriptor(c).c_str(), c.Decode());
return false;
}
return true;
@@ -660,7 +660,7 @@
if (!CheckArray(soa, array)) {
return false;
}
- mirror::Array* a = soa.Decode<mirror::Array*>(array);
+ ObjPtr<mirror::Array> a = soa.Decode<mirror::Array>(array);
if (a->GetClass()->GetComponentType()->GetPrimitiveType() != type) {
AbortF("incompatible array type %s expected %s[]: %p",
PrettyDescriptor(a->GetClass()).c_str(), PrettyDescriptor(type).c_str(), array);
@@ -692,20 +692,20 @@
return false;
}
if (is_static) {
- mirror::Object* o = soa.Decode<mirror::Object*>(obj);
+ ObjPtr<mirror::Object> o = soa.Decode<mirror::Object>(obj);
if (o == nullptr || !o->IsClass()) {
AbortF("attempt to access static field %s with a class argument of type %s: %p",
PrettyField(field).c_str(), PrettyTypeOf(o).c_str(), fid);
return false;
}
- mirror::Class* c = o->AsClass();
- if (field->GetDeclaringClass() != c) {
+ ObjPtr<mirror::Class> c = o->AsClass();
+ if (c != field->GetDeclaringClass()) {
AbortF("attempt to access static field %s with an incompatible class argument of %s: %p",
PrettyField(field).c_str(), PrettyDescriptor(c).c_str(), fid);
return false;
}
} else {
- mirror::Object* o = soa.Decode<mirror::Object*>(obj);
+ ObjPtr<mirror::Object> o = soa.Decode<mirror::Object>(obj);
if (o == nullptr || !field->GetDeclaringClass()->IsAssignableFrom(o->GetClass())) {
AbortF("attempt to access field %s from an object argument of type %s: %p",
PrettyField(field).c_str(), PrettyTypeOf(o).c_str(), fid);
@@ -763,7 +763,7 @@
}
}
- mirror::Object* obj = soa.Decode<mirror::Object*>(java_object);
+ ObjPtr<mirror::Object> obj = soa.Decode<mirror::Object>(java_object);
if (obj == nullptr) {
// Either java_object is invalid or is a cleared weak.
IndirectRef ref = reinterpret_cast<IndirectRef>(java_object);
@@ -772,12 +772,12 @@
okay = false;
} else {
obj = soa.Vm()->DecodeWeakGlobal(soa.Self(), ref);
- okay = Runtime::Current()->IsClearedJniWeakGlobal(obj);
+ okay = Runtime::Current()->IsClearedJniWeakGlobal(obj.Decode());
}
if (!okay) {
AbortF("%s is an invalid %s: %p (%p)",
what, ToStr<IndirectRefKind>(GetIndirectRefKind(java_object)).c_str(),
- java_object, obj);
+ java_object, obj.Decode());
return false;
}
}
@@ -786,7 +786,7 @@
Runtime::Current()->GetHeap()->DumpSpaces(LOG_STREAM(ERROR));
AbortF("%s is an invalid %s: %p (%p)",
what, ToStr<IndirectRefKind>(GetIndirectRefKind(java_object)).c_str(),
- java_object, obj);
+ java_object, obj.Decode());
return false;
}
@@ -936,10 +936,10 @@
break;
case 'c': { // jclass
jclass jc = arg.c;
- mirror::Class* c = soa.Decode<mirror::Class*>(jc);
+ ObjPtr<mirror::Class> c = soa.Decode<mirror::Class>(jc);
if (c == nullptr) {
*msg += "NULL";
- } else if (!Runtime::Current()->GetHeap()->IsValidObjectAddress(c)) {
+ } else if (!Runtime::Current()->GetHeap()->IsValidObjectAddress(c.Decode())) {
StringAppendF(msg, "INVALID POINTER:%p", jc);
} else if (!c->IsClass()) {
*msg += "INVALID NON-CLASS OBJECT OF TYPE:" + PrettyTypeOf(c);
@@ -1107,12 +1107,12 @@
return false;
}
- mirror::Array* a = soa.Decode<mirror::Array*>(java_array);
- if (UNLIKELY(!Runtime::Current()->GetHeap()->IsValidObjectAddress(a))) {
+ ObjPtr<mirror::Array> a = soa.Decode<mirror::Array>(java_array);
+ if (UNLIKELY(!Runtime::Current()->GetHeap()->IsValidObjectAddress(a.Decode()))) {
Runtime::Current()->GetHeap()->DumpSpaces(LOG_STREAM(ERROR));
AbortF("jarray is an invalid %s: %p (%p)",
ToStr<IndirectRefKind>(GetIndirectRefKind(java_array)).c_str(),
- java_array, a);
+ java_array, a.Decode());
return false;
} else if (!a->IsArrayInstance()) {
AbortF("jarray argument has non-array type: %s", PrettyTypeOf(a).c_str());
@@ -1411,7 +1411,7 @@
void* original_ptr) {
ScopedObjectAccess soa(env);
- mirror::Array* a = soa.Decode<mirror::Array*>(java_array);
+ ObjPtr<mirror::Array> a = soa.Decode<mirror::Array>(java_array);
size_t component_size = a->GetClass()->GetComponentSize();
size_t byte_count = a->GetLength() * component_size;
void* result = Create(original_ptr, byte_count, true);
diff --git a/runtime/check_reference_map_visitor.h b/runtime/check_reference_map_visitor.h
index 843d4c1..ab712f9 100644
--- a/runtime/check_reference_map_visitor.h
+++ b/runtime/check_reference_map_visitor.h
@@ -19,7 +19,7 @@
#include "art_method-inl.h"
#include "oat_quick_method_header.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
#include "stack_map.h"
namespace art {
diff --git a/runtime/class_linker-inl.h b/runtime/class_linker-inl.h
index caabcde..51e5aae 100644
--- a/runtime/class_linker-inl.h
+++ b/runtime/class_linker-inl.h
@@ -67,9 +67,10 @@
// MethodVerifier refuses methods with string_idx out of bounds.
DCHECK_LT(string_idx, declaring_class->GetDexFile().NumStringIds());;
mirror::String* string =
- mirror::StringDexCachePair::LookupString(declaring_class->GetDexCacheStrings(),
- string_idx,
- mirror::DexCache::kDexCacheStringCacheSize).Read();
+ mirror::StringDexCachePair::Lookup(declaring_class->GetDexCacheStrings(),
+ string_idx,
+ mirror::DexCache::kDexCacheStringCacheSize).Read();
+ Thread::PoisonObjectPointersIfDebug();
if (UNLIKELY(string == nullptr)) {
StackHandleScope<1> hs(Thread::Current());
Handle<mirror::DexCache> dex_cache(hs.NewHandle(declaring_class->GetDexCache()));
@@ -84,6 +85,7 @@
inline mirror::Class* ClassLinker::ResolveType(uint16_t type_idx, ArtMethod* referrer) {
mirror::Class* resolved_type = referrer->GetDexCacheResolvedType(type_idx, image_pointer_size_);
+ Thread::PoisonObjectPointersIfDebug();
if (UNLIKELY(resolved_type == nullptr)) {
mirror::Class* declaring_class = referrer->GetDeclaringClass();
StackHandleScope<2> hs(Thread::Current());
@@ -101,6 +103,7 @@
mirror::Class* declaring_class = referrer->GetDeclaringClass();
mirror::DexCache* dex_cache_ptr = declaring_class->GetDexCache();
mirror::Class* resolved_type = dex_cache_ptr->GetResolvedType(type_idx);
+ Thread::PoisonObjectPointersIfDebug();
if (UNLIKELY(resolved_type == nullptr)) {
StackHandleScope<2> hs(Thread::Current());
Handle<mirror::DexCache> dex_cache(hs.NewHandle(dex_cache_ptr));
@@ -148,6 +151,7 @@
ArtMethod* referrer,
InvokeType type) {
ArtMethod* resolved_method = GetResolvedMethod(method_idx, referrer);
+ Thread::PoisonObjectPointersIfDebug();
if (UNLIKELY(resolved_method == nullptr)) {
mirror::Class* declaring_class = referrer->GetDeclaringClass();
StackHandleScope<2> hs(self);
@@ -179,6 +183,7 @@
bool is_static) {
mirror::Class* declaring_class = referrer->GetDeclaringClass();
ArtField* resolved_field = GetResolvedField(field_idx, declaring_class);
+ Thread::PoisonObjectPointersIfDebug();
if (UNLIKELY(resolved_field == nullptr)) {
StackHandleScope<2> hs(Thread::Current());
Handle<mirror::DexCache> dex_cache(hs.NewHandle(declaring_class->GetDexCache()));
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index c51b99a..0a1f7a9 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -73,6 +73,8 @@
#include "mirror/field.h"
#include "mirror/iftable-inl.h"
#include "mirror/method.h"
+#include "mirror/method_type.h"
+#include "mirror/method_handle_impl.h"
#include "mirror/object-inl.h"
#include "mirror/object_array-inl.h"
#include "mirror/proxy.h"
@@ -89,7 +91,7 @@
#include "os.h"
#include "runtime.h"
#include "ScopedLocalRef.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
#include "thread-inl.h"
#include "trace.h"
#include "utils.h"
@@ -636,6 +638,18 @@
SetClassRoot(kJavaLangReflectMethodArrayClass, class_root);
mirror::Method::SetArrayClass(class_root);
+ // Create java.lang.invoke.MethodType.class root
+ class_root = FindSystemClass(self, "Ljava/lang/invoke/MethodType;");
+ CHECK(class_root != nullptr);
+ SetClassRoot(kJavaLangInvokeMethodType, class_root);
+ mirror::MethodType::SetClass(class_root);
+
+ // Create java.lang.invoke.MethodHandleImpl.class root
+ class_root = FindSystemClass(self, "Ljava/lang/invoke/MethodHandleImpl;");
+ CHECK(class_root != nullptr);
+ SetClassRoot(kJavaLangInvokeMethodHandleImpl, class_root);
+ mirror::MethodHandleImpl::SetClass(class_root);
+
// java.lang.ref classes need to be specially flagged, but otherwise are normal classes
// finish initializing Reference class
mirror::Class::SetStatus(java_lang_ref_Reference, mirror::Class::kStatusNotReady, self);
@@ -1032,6 +1046,8 @@
mirror::Constructor::SetArrayClass(GetClassRoot(kJavaLangReflectConstructorArrayClass));
mirror::Method::SetClass(GetClassRoot(kJavaLangReflectMethod));
mirror::Method::SetArrayClass(GetClassRoot(kJavaLangReflectMethodArrayClass));
+ mirror::MethodType::SetClass(GetClassRoot(kJavaLangInvokeMethodType));
+ mirror::MethodHandleImpl::SetClass(GetClassRoot(kJavaLangInvokeMethodHandleImpl));
mirror::Reference::SetClass(GetClassRoot(kJavaLangRefReference));
mirror::BooleanArray::SetArrayClass(GetClassRoot(kBooleanArrayClass));
mirror::ByteArray::SetArrayClass(GetClassRoot(kByteArrayClass));
@@ -1069,8 +1085,8 @@
bool ClassLinker::IsBootClassLoader(ScopedObjectAccessAlreadyRunnable& soa,
mirror::ClassLoader* class_loader) {
return class_loader == nullptr ||
- class_loader->GetClass() ==
- soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_BootClassLoader);
+ soa.Decode<mirror::Class>(WellKnownClasses::java_lang_BootClassLoader) ==
+ class_loader->GetClass();
}
static mirror::String* GetDexPathListElementName(ScopedObjectAccessUnchecked& soa,
@@ -1109,8 +1125,8 @@
CHECK(dex_path_list_field != nullptr);
CHECK(dex_elements_field != nullptr);
while (!ClassLinker::IsBootClassLoader(soa, class_loader)) {
- if (class_loader->GetClass() !=
- soa.Decode<mirror::Class*>(WellKnownClasses::dalvik_system_PathClassLoader)) {
+ if (soa.Decode<mirror::Class>(WellKnownClasses::dalvik_system_PathClassLoader) !=
+ class_loader->GetClass()) {
*error_msg = StringPrintf("Unknown class loader type %s", PrettyTypeOf(class_loader).c_str());
// Unsupported class loader.
return false;
@@ -1292,8 +1308,8 @@
mirror::StringDexCacheType* const strings =
reinterpret_cast<mirror::StringDexCacheType*>(raw_arrays + layout.StringsOffset());
for (size_t j = 0; j < num_strings; ++j) {
- DCHECK_EQ(strings[j].load(std::memory_order_relaxed).string_index, 0u);
- DCHECK(strings[j].load(std::memory_order_relaxed).string_pointer.IsNull());
+ DCHECK_EQ(strings[j].load(std::memory_order_relaxed).index, 0u);
+ DCHECK(strings[j].load(std::memory_order_relaxed).object.IsNull());
strings[j].store(image_resolved_strings[j].load(std::memory_order_relaxed),
std::memory_order_relaxed);
}
@@ -1687,7 +1703,7 @@
return false;
}
// Add the temporary dex path list elements at the end.
- auto* elements = soa.Decode<mirror::ObjectArray<mirror::Object>*>(dex_elements);
+ auto elements = soa.Decode<mirror::ObjectArray<mirror::Object>>(dex_elements);
for (size_t i = 0, num_elems = elements->GetLength(); i < num_elems; ++i) {
mirror::Object* element = elements->GetWithoutChecks(i);
if (element != nullptr) {
@@ -2032,6 +2048,8 @@
mirror::IntArray::ResetArrayClass();
mirror::LongArray::ResetArrayClass();
mirror::ShortArray::ResetArrayClass();
+ mirror::MethodType::ResetClass();
+ mirror::MethodHandleImpl::ResetClass();
Thread* const self = Thread::Current();
for (const ClassLoaderData& data : class_loaders_) {
DeleteClassLoader(self, data);
@@ -2109,8 +2127,8 @@
if (kIsDebugBuild) {
// Sanity check to make sure all the dex cache arrays are empty. b/28992179
for (size_t i = 0; i < num_strings; ++i) {
- CHECK_EQ(strings[i].load(std::memory_order_relaxed).string_index, 0u);
- CHECK(strings[i].load(std::memory_order_relaxed).string_pointer.IsNull());
+ CHECK_EQ(strings[i].load(std::memory_order_relaxed).index, 0u);
+ CHECK(strings[i].load(std::memory_order_relaxed).object.IsNull());
}
for (size_t i = 0; i < dex_file.NumTypeIds(); ++i) {
CHECK(types[i].Read<kWithoutReadBarrier>() == nullptr);
@@ -2169,6 +2187,7 @@
const char* descriptor,
mirror::Class* klass) {
DCHECK(klass != nullptr);
+ Thread::PoisonObjectPointersIfDebug();
// For temporary classes we must wait for them to be retired.
if (init_done_ && klass->IsTemp()) {
@@ -2285,8 +2304,8 @@
}
// Unsupported class-loader?
- if (class_loader->GetClass() !=
- soa.Decode<mirror::Class*>(WellKnownClasses::dalvik_system_PathClassLoader)) {
+ if (soa.Decode<mirror::Class>(WellKnownClasses::dalvik_system_PathClassLoader) !=
+ class_loader->GetClass()) {
*result = nullptr;
return false;
}
@@ -2380,7 +2399,7 @@
DCHECK_NE(*descriptor, '\0') << "descriptor is empty string";
DCHECK(self != nullptr);
self->AssertNoPendingException();
- self->PoisonObjectPointers();
+ self->PoisonObjectPointers(); // For DefineClass, CreateArrayClass, etc...
if (descriptor[1] == '\0') {
// only the descriptors of primitive types should be 1 character long, also avoid class lookup
// for primitive classes that aren't backed by dex files.
@@ -2463,7 +2482,7 @@
return nullptr;
} else {
// success, return mirror::Class*
- return soa.Decode<mirror::Class*>(result.get());
+ return soa.Decode<mirror::Class>(result.get()).Decode();
}
}
UNREACHABLE();
@@ -4186,9 +4205,9 @@
// Set the class access flags incl. VerificationAttempted, so we do not try to set the flag on
// the methods.
klass->SetAccessFlags(kAccClassIsProxy | kAccPublic | kAccFinal | kAccVerificationAttempted);
- klass->SetClassLoader(soa.Decode<mirror::ClassLoader*>(loader));
+ klass->SetClassLoader(soa.Decode<mirror::ClassLoader>(loader).Decode());
DCHECK_EQ(klass->GetPrimitiveType(), Primitive::kPrimNot);
- klass->SetName(soa.Decode<mirror::String*>(name));
+ klass->SetName(soa.Decode<mirror::String>(name).Decode());
klass->SetDexCache(GetClassRoot(kJavaLangReflectProxy)->GetDexCache());
mirror::Class::SetStatus(klass, mirror::Class::kStatusIdx, self);
std::string descriptor(GetDescriptorForProxy(klass.Get()));
@@ -4226,7 +4245,7 @@
const size_t num_direct_methods = 1;
// They have as many virtual methods as the array
- auto h_methods = hs.NewHandle(soa.Decode<mirror::ObjectArray<mirror::Method>*>(methods));
+ auto h_methods = hs.NewHandle(soa.Decode<mirror::ObjectArray<mirror::Method>>(methods));
DCHECK_EQ(h_methods->GetClass(), mirror::Method::ArrayClass())
<< PrettyClass(h_methods->GetClass());
const size_t num_virtual_methods = h_methods->GetLength();
@@ -4268,7 +4287,7 @@
// Link the fields and virtual methods, creating vtable and iftables.
// The new class will replace the old one in the class table.
Handle<mirror::ObjectArray<mirror::Class>> h_interfaces(
- hs.NewHandle(soa.Decode<mirror::ObjectArray<mirror::Class>*>(interfaces)));
+ hs.NewHandle(soa.Decode<mirror::ObjectArray<mirror::Class>>(interfaces)));
if (!LinkClass(self, descriptor.c_str(), klass, h_interfaces, &new_class)) {
mirror::Class::SetStatus(klass, mirror::Class::kStatusError, self);
return nullptr;
@@ -4279,11 +4298,13 @@
klass.Assign(new_class.Get());
CHECK_EQ(interfaces_sfield.GetDeclaringClass(), klass.Get());
- interfaces_sfield.SetObject<false>(klass.Get(),
- soa.Decode<mirror::ObjectArray<mirror::Class>*>(interfaces));
+ interfaces_sfield.SetObject<false>(
+ klass.Get(),
+ soa.Decode<mirror::ObjectArray<mirror::Class>>(interfaces).Decode());
CHECK_EQ(throws_sfield.GetDeclaringClass(), klass.Get());
throws_sfield.SetObject<false>(
- klass.Get(), soa.Decode<mirror::ObjectArray<mirror::ObjectArray<mirror::Class> >*>(throws));
+ klass.Get(),
+ soa.Decode<mirror::ObjectArray<mirror::ObjectArray<mirror::Class>>>(throws).Decode());
{
// Lock on klass is released. Lock new class object.
@@ -4303,7 +4324,7 @@
}
StackHandleScope<1> hs2(self);
- Handle<mirror::String> decoded_name = hs2.NewHandle(soa.Decode<mirror::String*>(name));
+ Handle<mirror::String> decoded_name = hs2.NewHandle(soa.Decode<mirror::String>(name));
std::string interfaces_field_name(StringPrintf("java.lang.Class[] %s.interfaces",
decoded_name->ToModifiedUtf8().c_str()));
CHECK_EQ(PrettyField(klass->GetStaticField(0)), interfaces_field_name);
@@ -4313,9 +4334,9 @@
CHECK_EQ(PrettyField(klass->GetStaticField(1)), throws_field_name);
CHECK_EQ(klass.Get()->GetInterfaces(),
- soa.Decode<mirror::ObjectArray<mirror::Class>*>(interfaces));
+ soa.Decode<mirror::ObjectArray<mirror::Class>>(interfaces).Decode());
CHECK_EQ(klass.Get()->GetThrows(),
- soa.Decode<mirror::ObjectArray<mirror::ObjectArray<mirror::Class>>*>(throws));
+ soa.Decode<mirror::ObjectArray<mirror::ObjectArray<mirror::Class>>>(throws).Decode());
}
return klass.Get();
}
@@ -7526,6 +7547,7 @@
Handle<mirror::DexCache> dex_cache) {
DCHECK(dex_cache.Get() != nullptr);
mirror::String* resolved = dex_cache->GetResolvedString(string_idx);
+ Thread::PoisonObjectPointersIfDebug();
if (resolved != nullptr) {
return resolved;
}
@@ -7568,6 +7590,7 @@
Handle<mirror::ClassLoader> class_loader) {
DCHECK(dex_cache.Get() != nullptr);
mirror::Class* resolved = dex_cache->GetResolvedType(type_idx);
+ Thread::PoisonObjectPointersIfDebug();
if (resolved == nullptr) {
Thread* self = Thread::Current();
const char* descriptor = dex_file.StringByTypeIdx(type_idx);
@@ -7606,6 +7629,7 @@
DCHECK(dex_cache.Get() != nullptr);
// Check for hit in the dex cache.
ArtMethod* resolved = dex_cache->GetResolvedMethod(method_idx, image_pointer_size_);
+ Thread::PoisonObjectPointersIfDebug();
if (resolved != nullptr && !resolved->IsRuntimeMethod()) {
DCHECK(resolved->GetDeclaringClassUnchecked() != nullptr) << resolved->GetDexMethodIndex();
if (kResolveMode == ClassLinker::kForceICCECheck) {
@@ -7809,6 +7833,7 @@
Handle<mirror::DexCache> dex_cache,
Handle<mirror::ClassLoader> class_loader) {
ArtMethod* resolved = dex_cache->GetResolvedMethod(method_idx, image_pointer_size_);
+ Thread::PoisonObjectPointersIfDebug();
if (resolved != nullptr && !resolved->IsRuntimeMethod()) {
DCHECK(resolved->GetDeclaringClassUnchecked() != nullptr) << resolved->GetDexMethodIndex();
return resolved;
@@ -7841,6 +7866,7 @@
bool is_static) {
DCHECK(dex_cache.Get() != nullptr);
ArtField* resolved = dex_cache->GetResolvedField(field_idx, image_pointer_size_);
+ Thread::PoisonObjectPointersIfDebug();
if (resolved != nullptr) {
return resolved;
}
@@ -7883,6 +7909,7 @@
Handle<mirror::ClassLoader> class_loader) {
DCHECK(dex_cache.Get() != nullptr);
ArtField* resolved = dex_cache->GetResolvedField(field_idx, image_pointer_size_);
+ Thread::PoisonObjectPointersIfDebug();
if (resolved != nullptr) {
return resolved;
}
@@ -8064,6 +8091,8 @@
"[Ljava/lang/reflect/Constructor;",
"[Ljava/lang/reflect/Field;",
"[Ljava/lang/reflect/Method;",
+ "Ljava/lang/invoke/MethodHandleImpl;",
+ "Ljava/lang/invoke/MethodType;",
"Ljava/lang/ClassLoader;",
"Ljava/lang/Throwable;",
"Ljava/lang/ClassNotFoundException;",
@@ -8166,7 +8195,7 @@
// Create PathClassLoader.
Handle<mirror::Class> h_path_class_class = hs.NewHandle(
- soa.Decode<mirror::Class*>(WellKnownClasses::dalvik_system_PathClassLoader));
+ soa.Decode<mirror::Class>(WellKnownClasses::dalvik_system_PathClassLoader));
Handle<mirror::Object> h_path_class_loader = hs.NewHandle(
h_path_class_class->AllocObject(self));
DCHECK(h_path_class_loader.Get() != nullptr);
@@ -8183,7 +8212,7 @@
"Ljava/lang/ClassLoader;");
DCHECK(parent_field != nullptr);
mirror::Object* boot_cl =
- soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_BootClassLoader)->AllocObject(self);
+ soa.Decode<mirror::Class>(WellKnownClasses::java_lang_BootClassLoader)->AllocObject(self);
parent_field->SetObject<false>(h_path_class_loader.Get(), boot_cl);
// Make it a global ref and return.
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index 954af76..8f7051e 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -51,6 +51,7 @@
class DexCachePointerArray;
class DexCacheTest_Open_Test;
class IfTable;
+ class MethodType;
template<class T> class ObjectArray;
class StackTraceElement;
} // namespace mirror
@@ -99,6 +100,8 @@
kJavaLangReflectConstructorArrayClass,
kJavaLangReflectFieldArrayClass,
kJavaLangReflectMethodArrayClass,
+ kJavaLangInvokeMethodHandleImpl,
+ kJavaLangInvokeMethodType,
kJavaLangClassLoader,
kJavaLangThrowable,
kJavaLangClassNotFoundException,
diff --git a/runtime/class_linker_test.cc b/runtime/class_linker_test.cc
index 7023081..a5aa0d0 100644
--- a/runtime/class_linker_test.cc
+++ b/runtime/class_linker_test.cc
@@ -33,6 +33,8 @@
#include "mirror/dex_cache.h"
#include "mirror/executable.h"
#include "mirror/field.h"
+#include "mirror/method_type.h"
+#include "mirror/method_handle_impl.h"
#include "mirror/object-inl.h"
#include "mirror/object_array-inl.h"
#include "mirror/proxy.h"
@@ -40,7 +42,7 @@
#include "mirror/stack_trace_element.h"
#include "mirror/string-inl.h"
#include "handle_scope-inl.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
#include "thread-inl.h"
namespace art {
@@ -708,6 +710,27 @@
};
};
+struct MethodTypeOffsets : public CheckOffsets<mirror::MethodType> {
+ MethodTypeOffsets() : CheckOffsets<mirror::MethodType>(
+ false, "Ljava/lang/invoke/MethodType;") {
+ addOffset(OFFSETOF_MEMBER(mirror::MethodType, form_), "form");
+ addOffset(OFFSETOF_MEMBER(mirror::MethodType, method_descriptor_), "methodDescriptor");
+ addOffset(OFFSETOF_MEMBER(mirror::MethodType, p_types_), "ptypes");
+ addOffset(OFFSETOF_MEMBER(mirror::MethodType, r_type_), "rtype");
+ addOffset(OFFSETOF_MEMBER(mirror::MethodType, wrap_alt_), "wrapAlt");
+ }
+};
+
+struct MethodHandleImplOffsets : public CheckOffsets<mirror::MethodHandleImpl> {
+ MethodHandleImplOffsets() : CheckOffsets<mirror::MethodHandleImpl>(
+ false, "Ljava/lang/invoke/MethodHandle;") {
+ addOffset(OFFSETOF_MEMBER(mirror::MethodHandleImpl, art_field_or_method_), "artFieldOrMethod");
+ addOffset(OFFSETOF_MEMBER(mirror::MethodHandleImpl, as_type_cache_), "asTypeCache");
+ addOffset(OFFSETOF_MEMBER(mirror::MethodHandleImpl, handle_kind_), "handleKind");
+ addOffset(OFFSETOF_MEMBER(mirror::MethodHandleImpl, method_type_), "type");
+ }
+};
+
// C++ fields must exactly match the fields in the Java classes. If this fails,
// reorder the fields in the C++ class. Managed class fields are ordered by
// ClassLinker::LinkFields.
@@ -726,6 +749,8 @@
EXPECT_TRUE(AccessibleObjectOffsets().Check());
EXPECT_TRUE(FieldOffsets().Check());
EXPECT_TRUE(ExecutableOffsets().Check());
+ EXPECT_TRUE(MethodTypeOffsets().Check());
+ EXPECT_TRUE(MethodHandleImplOffsets().Check());
}
TEST_F(ClassLinkerTest, FindClassNonexistent) {
@@ -752,7 +777,7 @@
ScopedObjectAccess soa(Thread::Current());
StackHandleScope<1> hs(soa.Self());
Handle<mirror::ClassLoader> class_loader(
- hs.NewHandle(soa.Decode<mirror::ClassLoader*>(LoadDex("Nested"))));
+ hs.NewHandle(soa.Decode<mirror::ClassLoader>(LoadDex("Nested"))));
mirror::Class* outer = class_linker_->FindClass(soa.Self(), "LNested;", class_loader);
ASSERT_TRUE(outer != nullptr);
@@ -786,7 +811,7 @@
StackHandleScope<1> hs(soa.Self());
Handle<mirror::ClassLoader> class_loader(
- hs.NewHandle(soa.Decode<mirror::ClassLoader*>(LoadDex("MyClass"))));
+ hs.NewHandle(soa.Decode<mirror::ClassLoader>(LoadDex("MyClass"))));
AssertNonExistentClass("LMyClass;");
mirror::Class* MyClass = class_linker_->FindClass(soa.Self(), "LMyClass;", class_loader);
ASSERT_TRUE(MyClass != nullptr);
@@ -912,9 +937,9 @@
ScopedObjectAccess soa(Thread::Current());
StackHandleScope<2> hs(soa.Self());
Handle<mirror::ClassLoader> class_loader_1(
- hs.NewHandle(soa.Decode<mirror::ClassLoader*>(LoadDex("MyClass"))));
+ hs.NewHandle(soa.Decode<mirror::ClassLoader>(LoadDex("MyClass"))));
Handle<mirror::ClassLoader> class_loader_2(
- hs.NewHandle(soa.Decode<mirror::ClassLoader*>(LoadDex("MyClass"))));
+ hs.NewHandle(soa.Decode<mirror::ClassLoader>(LoadDex("MyClass"))));
mirror::Class* MyClass_1 = class_linker_->FindClass(soa.Self(), "LMyClass;", class_loader_1);
mirror::Class* MyClass_2 = class_linker_->FindClass(soa.Self(), "LMyClass;", class_loader_2);
EXPECT_TRUE(MyClass_1 != nullptr);
@@ -926,7 +951,7 @@
ScopedObjectAccess soa(Thread::Current());
StackHandleScope<2> hs(soa.Self());
Handle<mirror::ClassLoader> class_loader(
- hs.NewHandle(soa.Decode<mirror::ClassLoader*>(LoadDex("Statics"))));
+ hs.NewHandle(soa.Decode<mirror::ClassLoader>(LoadDex("Statics"))));
Handle<mirror::Class> statics(
hs.NewHandle(class_linker_->FindClass(soa.Self(), "LStatics;", class_loader)));
class_linker_->EnsureInitialized(soa.Self(), statics, true, true);
@@ -1003,7 +1028,7 @@
ScopedObjectAccess soa(Thread::Current());
StackHandleScope<6> hs(soa.Self());
Handle<mirror::ClassLoader> class_loader(
- hs.NewHandle(soa.Decode<mirror::ClassLoader*>(LoadDex("Interfaces"))));
+ hs.NewHandle(soa.Decode<mirror::ClassLoader>(LoadDex("Interfaces"))));
Handle<mirror::Class> I(
hs.NewHandle(class_linker_->FindClass(soa.Self(), "LInterfaces$I;", class_loader)));
Handle<mirror::Class> J(
@@ -1072,7 +1097,7 @@
const DexFile* dex_file = GetFirstDexFile(jclass_loader);
StackHandleScope<1> hs(soa.Self());
Handle<mirror::ClassLoader> class_loader(
- hs.NewHandle(soa.Decode<mirror::ClassLoader*>(jclass_loader)));
+ hs.NewHandle(soa.Decode<mirror::ClassLoader>(jclass_loader)));
mirror::Class* klass = class_linker_->FindClass(soa.Self(), "LStaticsFromCode;", class_loader);
ArtMethod* clinit = klass->FindClassInitializer(kRuntimePointerSize);
ArtMethod* getS0 = klass->FindDirectMethod("getS0", "()Ljava/lang/Object;", kRuntimePointerSize);
@@ -1202,7 +1227,7 @@
StackHandleScope<2> hs(soa.Self());
Handle<mirror::ClassLoader> class_loader(
- hs.NewHandle(soa.Decode<mirror::ClassLoader*>(LoadDex("Statics"))));
+ hs.NewHandle(soa.Decode<mirror::ClassLoader>(LoadDex("Statics"))));
Handle<mirror::Class> statics(
hs.NewHandle(class_linker_->FindClass(soa.Self(), "LStatics;", class_loader)));
@@ -1217,7 +1242,7 @@
StackHandleScope<3> hs(soa.Self());
Handle<mirror::ClassLoader> class_loader(
- hs.NewHandle(soa.Decode<mirror::ClassLoader*>(LoadDex("Statics"))));
+ hs.NewHandle(soa.Decode<mirror::ClassLoader>(LoadDex("Statics"))));
// java.lang.Object is a bootstrap class.
Handle<mirror::Class> jlo_class(
diff --git a/runtime/common_runtime_test.cc b/runtime/common_runtime_test.cc
index 11722b2..eda1ddd 100644
--- a/runtime/common_runtime_test.cc
+++ b/runtime/common_runtime_test.cc
@@ -47,7 +47,7 @@
#include "os.h"
#include "primitive.h"
#include "runtime-inl.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
#include "thread.h"
#include "well_known_classes.h"
@@ -511,12 +511,12 @@
StackHandleScope<2> hs(soa.Self());
Handle<mirror::ClassLoader> class_loader = hs.NewHandle(
- soa.Decode<mirror::ClassLoader*>(jclass_loader));
+ soa.Decode<mirror::ClassLoader>(jclass_loader));
DCHECK_EQ(class_loader->GetClass(),
- soa.Decode<mirror::Class*>(WellKnownClasses::dalvik_system_PathClassLoader));
+ soa.Decode<mirror::Class>(WellKnownClasses::dalvik_system_PathClassLoader).Decode());
DCHECK_EQ(class_loader->GetParent()->GetClass(),
- soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_BootClassLoader));
+ soa.Decode<mirror::Class>(WellKnownClasses::java_lang_BootClassLoader).Decode());
// The class loader is a PathClassLoader which inherits from BaseDexClassLoader.
// We need to get the DexPathList and loop through it.
diff --git a/runtime/debugger.cc b/runtime/debugger.cc
index 6ed44fc..0206cae 100644
--- a/runtime/debugger.cc
+++ b/runtime/debugger.cc
@@ -48,7 +48,7 @@
#include "mirror/throwable.h"
#include "reflection.h"
#include "safe_map.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
#include "ScopedLocalRef.h"
#include "ScopedPrimitiveArray.h"
#include "handle_scope-inl.h"
@@ -390,7 +390,8 @@
return nullptr;
}
- mirror::Class* java_lang_Thread = soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_Thread);
+ ObjPtr<mirror::Class> java_lang_Thread =
+ soa.Decode<mirror::Class>(WellKnownClasses::java_lang_Thread);
if (!java_lang_Thread->IsAssignableFrom(thread_peer->GetClass())) {
// This isn't a thread.
*error = JDWP::ERR_INVALID_THREAD;
@@ -431,21 +432,22 @@
return JDWP::JT_CLASS_OBJECT;
}
{
- mirror::Class* thread_class = soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_Thread);
+ ObjPtr<mirror::Class> thread_class =
+ soa.Decode<mirror::Class>(WellKnownClasses::java_lang_Thread);
if (thread_class->IsAssignableFrom(c)) {
return JDWP::JT_THREAD;
}
}
{
- mirror::Class* thread_group_class =
- soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_ThreadGroup);
+ ObjPtr<mirror::Class> thread_group_class =
+ soa.Decode<mirror::Class>(WellKnownClasses::java_lang_ThreadGroup);
if (thread_group_class->IsAssignableFrom(c)) {
return JDWP::JT_THREAD_GROUP;
}
}
{
- mirror::Class* class_loader_class =
- soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_ClassLoader);
+ ObjPtr<mirror::Class> class_loader_class =
+ soa.Decode<mirror::Class>(WellKnownClasses::java_lang_ClassLoader);
if (class_loader_class->IsAssignableFrom(c)) {
return JDWP::JT_CLASS_LOADER;
}
@@ -1946,7 +1948,8 @@
}
{
ScopedObjectAccessUnchecked soa(Thread::Current());
- mirror::Class* java_lang_String = soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_String);
+ ObjPtr<mirror::Class> java_lang_String =
+ soa.Decode<mirror::Class>(WellKnownClasses::java_lang_String);
if (!java_lang_String->IsAssignableFrom(obj->GetClass())) {
// This isn't a string.
return JDWP::ERR_INVALID_STRING;
@@ -2014,7 +2017,7 @@
expandBufAddObjectId(pReply, JDWP::ObjectId(0));
error = JDWP::ERR_NONE;
} else if (error == JDWP::ERR_NONE) {
- mirror::Class* c = soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_Thread);
+ ObjPtr<mirror::Class> c = soa.Decode<mirror::Class>(WellKnownClasses::java_lang_Thread);
CHECK(c != nullptr);
ArtField* f = soa.DecodeField(WellKnownClasses::java_lang_Thread_group);
CHECK(f != nullptr);
@@ -2038,7 +2041,8 @@
*error = JDWP::ERR_INVALID_OBJECT;
return nullptr;
}
- mirror::Class* c = soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_ThreadGroup);
+ ObjPtr<mirror::Class> c =
+ soa.Decode<mirror::Class>(WellKnownClasses::java_lang_ThreadGroup);
CHECK(c != nullptr);
if (!c->IsAssignableFrom(thread_group->GetClass())) {
// This is not a java.lang.ThreadGroup.
diff --git a/runtime/dex_file_annotations.cc b/runtime/dex_file_annotations.cc
index e0d5337..5763479 100644
--- a/runtime/dex_file_annotations.cc
+++ b/runtime/dex_file_annotations.cc
@@ -255,7 +255,7 @@
}
mirror::Class* annotation_member_class =
- soa.Decode<mirror::Class*>(WellKnownClasses::libcore_reflect_AnnotationMember);
+ soa.Decode<mirror::Class>(WellKnownClasses::libcore_reflect_AnnotationMember).Decode();
mirror::Class* annotation_member_array_class =
class_linker->FindArrayClass(self, &annotation_member_class);
if (annotation_member_array_class == nullptr) {
@@ -572,7 +572,7 @@
*annotation_ptr = annotation;
if (result_style == DexFile::kAllObjects && primitive_type != Primitive::kPrimVoid) {
- element_object = BoxPrimitive(primitive_type, annotation_value->value_);
+ element_object = BoxPrimitive(primitive_type, annotation_value->value_).Decode();
set_object = true;
}
@@ -782,7 +782,7 @@
ScopedObjectAccessUnchecked soa(self);
StackHandleScope<2> hs(self);
Handle<mirror::Class> annotation_array_class(hs.NewHandle(
- soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_annotation_Annotation__array)));
+ soa.Decode<mirror::Class>(WellKnownClasses::java_lang_annotation_Annotation__array)));
if (annotation_set == nullptr) {
return mirror::ObjectArray<mirror::Object>::Alloc(self, annotation_array_class.Get(), 0);
}
@@ -840,7 +840,7 @@
ScopedObjectAccessUnchecked soa(self);
StackHandleScope<1> hs(self);
mirror::Class* annotation_array_class =
- soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_annotation_Annotation__array);
+ soa.Decode<mirror::Class>(WellKnownClasses::java_lang_annotation_Annotation__array).Decode();
mirror::Class* annotation_array_array_class =
Runtime::Current()->GetClassLinker()->FindArrayClass(self, &annotation_array_class);
if (annotation_array_array_class == nullptr) {
diff --git a/runtime/dex_file_test.cc b/runtime/dex_file_test.cc
index 8dd5f37..8e1501f 100644
--- a/runtime/dex_file_test.cc
+++ b/runtime/dex_file_test.cc
@@ -24,7 +24,7 @@
#include "dex_file-inl.h"
#include "mem_map.h"
#include "os.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
#include "thread-inl.h"
#include "utils.h"
diff --git a/runtime/dex_file_verifier_test.cc b/runtime/dex_file_verifier_test.cc
index c5a4d75..e392870 100644
--- a/runtime/dex_file_verifier_test.cc
+++ b/runtime/dex_file_verifier_test.cc
@@ -27,7 +27,7 @@
#include "common_runtime_test.h"
#include "dex_file-inl.h"
#include "leb128.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
#include "thread-inl.h"
#include "utils.h"
diff --git a/runtime/dex_method_iterator_test.cc b/runtime/dex_method_iterator_test.cc
index 2681ad0..9f28c8c 100644
--- a/runtime/dex_method_iterator_test.cc
+++ b/runtime/dex_method_iterator_test.cc
@@ -19,7 +19,7 @@
#include "base/stl_util.h"
#include "common_runtime_test.h"
#include "oat_file.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
#include "thread-inl.h"
namespace art {
diff --git a/runtime/entrypoints/entrypoint_utils.cc b/runtime/entrypoints/entrypoint_utils.cc
index fd9ffbd..38ee468 100644
--- a/runtime/entrypoints/entrypoint_utils.cc
+++ b/runtime/entrypoints/entrypoint_utils.cc
@@ -33,7 +33,7 @@
#include "nth_caller_visitor.h"
#include "oat_quick_method_header.h"
#include "reflection.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
#include "well_known_classes.h"
namespace art {
@@ -160,12 +160,12 @@
} else {
JValue jv;
jv.SetJ(args.at(i).j);
- mirror::Object* val = BoxPrimitive(Primitive::GetType(shorty[i + 1]), jv);
+ mirror::Object* val = BoxPrimitive(Primitive::GetType(shorty[i + 1]), jv).Decode();
if (val == nullptr) {
CHECK(soa.Self()->IsExceptionPending());
return zero;
}
- soa.Decode<mirror::ObjectArray<mirror::Object>* >(args_jobj)->Set<false>(i, val);
+ soa.Decode<mirror::ObjectArray<mirror::Object>>(args_jobj)->Set<false>(i, val);
}
}
}
@@ -187,13 +187,13 @@
return zero;
} else {
ArtMethod* interface_method =
- soa.Decode<mirror::Method*>(interface_method_jobj)->GetArtMethod();
+ soa.Decode<mirror::Method>(interface_method_jobj)->GetArtMethod();
// This can cause thread suspension.
PointerSize pointer_size = Runtime::Current()->GetClassLinker()->GetImagePointerSize();
mirror::Class* result_type = interface_method->GetReturnType(true /* resolve */, pointer_size);
- mirror::Object* result_ref = soa.Decode<mirror::Object*>(result);
+ ObjPtr<mirror::Object> result_ref = soa.Decode<mirror::Object>(result);
JValue result_unboxed;
- if (!UnboxPrimitiveForResult(result_ref, result_type, &result_unboxed)) {
+ if (!UnboxPrimitiveForResult(result_ref.Decode(), result_type, &result_unboxed)) {
DCHECK(soa.Self()->IsExceptionPending());
return zero;
}
@@ -207,9 +207,9 @@
bool declares_exception = false;
{
ScopedAssertNoThreadSuspension ants(__FUNCTION__);
- mirror::Object* rcvr = soa.Decode<mirror::Object*>(rcvr_jobj);
+ ObjPtr<mirror::Object> rcvr = soa.Decode<mirror::Object>(rcvr_jobj);
mirror::Class* proxy_class = rcvr->GetClass();
- mirror::Method* interface_method = soa.Decode<mirror::Method*>(interface_method_jobj);
+ ObjPtr<mirror::Method> interface_method = soa.Decode<mirror::Method>(interface_method_jobj);
ArtMethod* proxy_method = rcvr->GetClass()->FindVirtualMethodForInterface(
interface_method->GetArtMethod(), kRuntimePointerSize);
auto virtual_methods = proxy_class->GetVirtualMethodsSlice(kRuntimePointerSize);
diff --git a/runtime/entrypoints/jni/jni_entrypoints.cc b/runtime/entrypoints/jni/jni_entrypoints.cc
index 22226c1..fd23ced 100644
--- a/runtime/entrypoints/jni/jni_entrypoints.cc
+++ b/runtime/entrypoints/jni/jni_entrypoints.cc
@@ -18,7 +18,7 @@
#include "base/logging.h"
#include "entrypoints/entrypoint_utils.h"
#include "mirror/object-inl.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
#include "thread.h"
namespace art {
diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
index cfd948e..c52bc8e 100644
--- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
@@ -36,7 +36,7 @@
#include "oat_quick_method_header.h"
#include "quick_exception_handler.h"
#include "runtime.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
#include "stack.h"
#include "debugger.h"
@@ -834,7 +834,7 @@
void BuildQuickArgumentVisitor::FixupReferences() {
// Fixup any references which may have changed.
for (const auto& pair : references_) {
- pair.second->Assign(soa_->Decode<mirror::Object*>(pair.first));
+ pair.second->Assign(soa_->Decode<mirror::Object>(pair.first).Decode());
soa_->Env()->DeleteLocalRef(pair.first);
}
}
@@ -926,7 +926,7 @@
void RememberForGcArgumentVisitor::FixupReferences() {
// Fixup any references which may have changed.
for (const auto& pair : references_) {
- pair.second->Assign(soa_->Decode<mirror::Object*>(pair.first));
+ pair.second->Assign(soa_->Decode<mirror::Object>(pair.first).Decode());
soa_->Env()->DeleteLocalRef(pair.first);
}
}
diff --git a/runtime/gc/accounting/card_table_test.cc b/runtime/gc/accounting/card_table_test.cc
index 819cb85..67ab14c 100644
--- a/runtime/gc/accounting/card_table_test.cc
+++ b/runtime/gc/accounting/card_table_test.cc
@@ -23,7 +23,7 @@
#include "handle_scope-inl.h"
#include "mirror/class-inl.h"
#include "mirror/string-inl.h" // Strings are easiest to allocate
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
#include "thread_pool.h"
#include "utils.h"
diff --git a/runtime/gc/collector/concurrent_copying.cc b/runtime/gc/collector/concurrent_copying.cc
index ab8942a..8b91075 100644
--- a/runtime/gc/collector/concurrent_copying.cc
+++ b/runtime/gc/collector/concurrent_copying.cc
@@ -32,7 +32,7 @@
#include "intern_table.h"
#include "mirror/class-inl.h"
#include "mirror/object-inl.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
#include "thread-inl.h"
#include "thread_list.h"
#include "well_known_classes.h"
diff --git a/runtime/gc/collector/mark_sweep.cc b/runtime/gc/collector/mark_sweep.cc
index ad3dd33..b89d99c 100644
--- a/runtime/gc/collector/mark_sweep.cc
+++ b/runtime/gc/collector/mark_sweep.cc
@@ -41,7 +41,7 @@
#include "mark_sweep-inl.h"
#include "mirror/object-inl.h"
#include "runtime.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
#include "thread-inl.h"
#include "thread_list.h"
diff --git a/runtime/gc/heap-inl.h b/runtime/gc/heap-inl.h
index b0ca18e..6d61c64 100644
--- a/runtime/gc/heap-inl.h
+++ b/runtime/gc/heap-inl.h
@@ -50,6 +50,7 @@
CHECK_EQ(self->GetState(), kRunnable);
self->AssertThreadSuspensionIsAllowable();
self->AssertNoPendingException();
+ self->PoisonObjectPointers();
}
// Need to check that we arent the large object allocator since the large object allocation code
// path this function. If we didn't check we would have an infinite loop.
diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc
index 4e6dd2b..88e4624 100644
--- a/runtime/gc/heap.cc
+++ b/runtime/gc/heap.cc
@@ -61,6 +61,7 @@
#include "intern_table.h"
#include "jit/jit.h"
#include "jit/jit_code_cache.h"
+#include "obj_ptr-inl.h"
#include "mirror/class-inl.h"
#include "mirror/object-inl.h"
#include "mirror/object_array-inl.h"
@@ -69,7 +70,7 @@
#include "reflection.h"
#include "runtime.h"
#include "ScopedLocalRef.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
#include "handle_scope-inl.h"
#include "thread_list.h"
#include "well_known_classes.h"
@@ -1507,13 +1508,14 @@
<< static_cast<int>(100 * managed_utilization) << "%.";
}
-bool Heap::IsValidObjectAddress(const mirror::Object* obj) const {
+bool Heap::IsValidObjectAddress(ObjPtr<mirror::Object> obj) const {
// Note: we deliberately don't take the lock here, and mustn't test anything that would require
// taking the lock.
if (obj == nullptr) {
return true;
}
- return IsAligned<kObjectAlignment>(obj) && FindSpaceFromObject(obj, true) != nullptr;
+ return IsAligned<kObjectAlignment>(obj.Decode()) &&
+ FindSpaceFromObject(obj.Decode(), true) != nullptr;
}
bool Heap::IsNonDiscontinuousSpaceHeapAddress(const mirror::Object* obj) const {
@@ -3565,9 +3567,9 @@
max_allowed_footprint_ = max_allowed_footprint;
}
-bool Heap::IsMovableObject(const mirror::Object* obj) const {
+bool Heap::IsMovableObject(ObjPtr<mirror::Object> obj) const {
if (kMovingCollector) {
- space::Space* space = FindContinuousSpaceFromObject(obj, true);
+ space::Space* space = FindContinuousSpaceFromObject(obj.Decode(), true);
if (space != nullptr) {
// TODO: Check large object?
return space->CanMoveObjects();
@@ -3727,7 +3729,7 @@
args[0].l = arg.get();
InvokeWithJValues(soa, nullptr, WellKnownClasses::java_lang_ref_FinalizerReference_add, args);
// Restore object in case it gets moved.
- *object = soa.Decode<mirror::Object*>(arg.get());
+ *object = soa.Decode<mirror::Object>(arg.get()).Decode();
}
void Heap::RequestConcurrentGCAndSaveObject(Thread* self, bool force_full, mirror::Object** obj) {
diff --git a/runtime/gc/heap.h b/runtime/gc/heap.h
index 10bebef..e32f057 100644
--- a/runtime/gc/heap.h
+++ b/runtime/gc/heap.h
@@ -34,6 +34,7 @@
#include "gc/collector_type.h"
#include "gc/space/large_object_space.h"
#include "globals.h"
+#include "obj_ptr.h"
#include "object_callbacks.h"
#include "offsets.h"
#include "process_state.h"
@@ -274,7 +275,7 @@
// A weaker test than IsLiveObject or VerifyObject that doesn't require the heap lock,
// and doesn't abort on error, allowing the caller to report more
// meaningful diagnostics.
- bool IsValidObjectAddress(const mirror::Object* obj) const REQUIRES_SHARED(Locks::mutator_lock_);
+ bool IsValidObjectAddress(ObjPtr<mirror::Object> obj) const REQUIRES_SHARED(Locks::mutator_lock_);
// Faster alternative to IsHeapAddress since finding if an object is in the large object space is
// very slow.
@@ -290,7 +291,7 @@
REQUIRES_SHARED(Locks::heap_bitmap_lock_, Locks::mutator_lock_);
// Returns true if there is any chance that the object (obj) will move.
- bool IsMovableObject(const mirror::Object* obj) const REQUIRES_SHARED(Locks::mutator_lock_);
+ bool IsMovableObject(ObjPtr<mirror::Object> obj) const REQUIRES_SHARED(Locks::mutator_lock_);
// Enables us to compacting GC until objects are released.
void IncrementDisableMovingGC(Thread* self) REQUIRES(!*gc_complete_lock_);
diff --git a/runtime/gc/heap_test.cc b/runtime/gc/heap_test.cc
index a3cefd9..515a6fd 100644
--- a/runtime/gc/heap_test.cc
+++ b/runtime/gc/heap_test.cc
@@ -22,7 +22,7 @@
#include "mirror/class-inl.h"
#include "mirror/object-inl.h"
#include "mirror/object_array-inl.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
namespace art {
namespace gc {
diff --git a/runtime/gc/reference_processor.cc b/runtime/gc/reference_processor.cc
index e172f85..9694597 100644
--- a/runtime/gc/reference_processor.cc
+++ b/runtime/gc/reference_processor.cc
@@ -24,7 +24,7 @@
#include "reference_processor-inl.h"
#include "reflection.h"
#include "ScopedLocalRef.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
#include "task_processor.h"
#include "utils.h"
#include "well_known_classes.h"
diff --git a/runtime/gc/reference_queue_test.cc b/runtime/gc/reference_queue_test.cc
index 2a1635d..5b8a3c2 100644
--- a/runtime/gc/reference_queue_test.cc
+++ b/runtime/gc/reference_queue_test.cc
@@ -20,7 +20,7 @@
#include "reference_queue.h"
#include "handle_scope-inl.h"
#include "mirror/class-inl.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
namespace art {
namespace gc {
diff --git a/runtime/gc/space/large_object_space.cc b/runtime/gc/space/large_object_space.cc
index 16d1f93..0030326 100644
--- a/runtime/gc/space/large_object_space.cc
+++ b/runtime/gc/space/large_object_space.cc
@@ -27,7 +27,7 @@
#include "base/stl_util.h"
#include "image.h"
#include "os.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
#include "space-inl.h"
#include "thread-inl.h"
diff --git a/runtime/gc/space/space_create_test.cc b/runtime/gc/space/space_create_test.cc
index 170f927..7bc4dc4 100644
--- a/runtime/gc/space/space_create_test.cc
+++ b/runtime/gc/space/space_create_test.cc
@@ -18,7 +18,7 @@
#include "dlmalloc_space.h"
#include "rosalloc_space.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
namespace art {
namespace gc {
diff --git a/runtime/gc/space/space_test.h b/runtime/gc/space/space_test.h
index bd600fe..17d7c87 100644
--- a/runtime/gc/space/space_test.h
+++ b/runtime/gc/space/space_test.h
@@ -26,7 +26,7 @@
#include "mirror/class-inl.h"
#include "mirror/class_loader.h"
#include "mirror/object-inl.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
#include "thread_list.h"
#include "zygote_space.h"
diff --git a/runtime/gc/system_weak_test.cc b/runtime/gc/system_weak_test.cc
index 7c1ec8a..af8a444 100644
--- a/runtime/gc/system_weak_test.cc
+++ b/runtime/gc/system_weak_test.cc
@@ -26,7 +26,7 @@
#include "handle_scope-inl.h"
#include "heap.h"
#include "mirror/string.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
#include "thread_list.h"
namespace art {
diff --git a/runtime/gc/task_processor.cc b/runtime/gc/task_processor.cc
index a49121b..0704a68 100644
--- a/runtime/gc/task_processor.cc
+++ b/runtime/gc/task_processor.cc
@@ -17,7 +17,7 @@
#include "task_processor.h"
#include "base/time_utils.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
namespace art {
namespace gc {
diff --git a/runtime/handle.h b/runtime/handle.h
index d4c13d4..c41010a 100644
--- a/runtime/handle.h
+++ b/runtime/handle.h
@@ -23,6 +23,7 @@
#include "base/mutex.h"
#include "base/value_object.h"
#include "jni.h"
+#include "obj_ptr.h"
#include "stack_reference.h"
namespace art {
@@ -130,6 +131,14 @@
return old;
}
+ ALWAYS_INLINE T* Assign(ObjPtr<T> reference) REQUIRES_SHARED(Locks::mutator_lock_) {
+ StackReference<mirror::Object>* ref = Handle<T>::GetReference();
+ T* old = down_cast<T*>(ref->AsMirrorPtr());
+ ref->Assign(reference.Decode());
+ return old;
+ }
+
+
template<typename S>
explicit MutableHandle(const MutableHandle<S>& handle) REQUIRES_SHARED(Locks::mutator_lock_)
: Handle<T>(handle) {
diff --git a/runtime/handle_scope-inl.h b/runtime/handle_scope-inl.h
index 2e1b8ed3..75a0391 100644
--- a/runtime/handle_scope-inl.h
+++ b/runtime/handle_scope-inl.h
@@ -21,6 +21,7 @@
#include "base/mutex.h"
#include "handle.h"
+#include "obj_ptr-inl.h"
#include "thread-inl.h"
#include "verify_object-inl.h"
@@ -107,12 +108,21 @@
return h;
}
+template<size_t kNumReferences> template<class MirrorType, bool kPoison>
+inline MutableHandle<MirrorType> StackHandleScope<kNumReferences>::NewHandle(
+ ObjPtr<MirrorType, kPoison> object) {
+ return NewHandle(object.Decode());
+}
+
template<size_t kNumReferences> template<class T>
inline HandleWrapper<T> StackHandleScope<kNumReferences>::NewHandleWrapper(T** object) {
- SetReference(pos_, *object);
- MutableHandle<T> h(GetHandle<T>(pos_));
- pos_++;
- return HandleWrapper<T>(object, h);
+ return HandleWrapper<T>(object, NewHandle(*object));
+}
+
+template<size_t kNumReferences> template<class T>
+inline HandleWrapperObjPtr<T> StackHandleScope<kNumReferences>::NewHandleWrapper(
+ ObjPtr<T>* object) {
+ return HandleWrapperObjPtr<T>(object, NewHandle(*object));
}
template<size_t kNumReferences>
diff --git a/runtime/handle_scope.h b/runtime/handle_scope.h
index 37eed99..2b283ae 100644
--- a/runtime/handle_scope.h
+++ b/runtime/handle_scope.h
@@ -28,6 +28,9 @@
#include "verify_object.h"
namespace art {
+
+template<class MirrorType, bool kPoison> class ObjPtr;
+
namespace mirror {
class Object;
}
@@ -125,7 +128,7 @@
};
// A wrapper which wraps around Object** and restores the pointer in the destructor.
-// TODO: Add more functionality.
+// TODO: Delete
template<class T>
class HandleWrapper : public MutableHandle<T> {
public:
@@ -143,6 +146,26 @@
T** const obj_;
};
+
+// A wrapper which wraps around ObjPtr<Object>* and restores the pointer in the destructor.
+// TODO: Add more functionality.
+template<class T>
+class HandleWrapperObjPtr : public MutableHandle<T> {
+ public:
+ HandleWrapperObjPtr(ObjPtr<T>* obj, const MutableHandle<T>& handle)
+ : MutableHandle<T>(handle), obj_(obj) {}
+
+ HandleWrapperObjPtr(const HandleWrapperObjPtr&) = default;
+
+ ~HandleWrapperObjPtr() {
+ *obj_ = ObjPtr<T>(MutableHandle<T>::Get());
+ }
+
+ private:
+ ObjPtr<T>* const obj_;
+};
+
+
// Scoped handle storage of a fixed size that is usually stack allocated.
template<size_t kNumReferences>
class PACKED(4) StackHandleScope FINAL : public HandleScope {
@@ -157,6 +180,14 @@
ALWAYS_INLINE HandleWrapper<T> NewHandleWrapper(T** object)
REQUIRES_SHARED(Locks::mutator_lock_);
+ template<class T>
+ ALWAYS_INLINE HandleWrapperObjPtr<T> NewHandleWrapper(ObjPtr<T>* object)
+ REQUIRES_SHARED(Locks::mutator_lock_);
+
+ template<class MirrorType, bool kPoison>
+ ALWAYS_INLINE MutableHandle<MirrorType> NewHandle(ObjPtr<MirrorType, kPoison> object)
+ REQUIRES_SHARED(Locks::mutator_lock_);
+
ALWAYS_INLINE void SetReference(size_t i, mirror::Object* object)
REQUIRES_SHARED(Locks::mutator_lock_);
diff --git a/runtime/handle_scope_test.cc b/runtime/handle_scope_test.cc
index 58f3800..c269a37 100644
--- a/runtime/handle_scope_test.cc
+++ b/runtime/handle_scope_test.cc
@@ -17,7 +17,7 @@
#include "base/enums.h"
#include "gtest/gtest.h"
#include "handle_scope-inl.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
#include "thread.h"
namespace art {
diff --git a/runtime/hprof/hprof.cc b/runtime/hprof/hprof.cc
index 921dde1..ecb2157 100644
--- a/runtime/hprof/hprof.cc
+++ b/runtime/hprof/hprof.cc
@@ -59,7 +59,7 @@
#include "mirror/object-inl.h"
#include "os.h"
#include "safe_map.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
#include "thread_list.h"
namespace art {
diff --git a/runtime/image.cc b/runtime/image.cc
index 7e6790a..299d5fd 100644
--- a/runtime/image.cc
+++ b/runtime/image.cc
@@ -25,7 +25,7 @@
namespace art {
const uint8_t ImageHeader::kImageMagic[] = { 'a', 'r', 't', '\n' };
-const uint8_t ImageHeader::kImageVersion[] = { '0', '3', '0', '\0' };
+const uint8_t ImageHeader::kImageVersion[] = { '0', '3', '1', '\0' };
ImageHeader::ImageHeader(uint32_t image_begin,
uint32_t image_size,
diff --git a/runtime/indirect_reference_table.cc b/runtime/indirect_reference_table.cc
index 1f39a1e..202e472 100644
--- a/runtime/indirect_reference_table.cc
+++ b/runtime/indirect_reference_table.cc
@@ -21,7 +21,7 @@
#include "nth_caller_visitor.h"
#include "reference_table.h"
#include "runtime.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
#include "thread.h"
#include "utils.h"
#include "verify_object-inl.h"
diff --git a/runtime/indirect_reference_table_test.cc b/runtime/indirect_reference_table_test.cc
index 61bcadd..58d487d 100644
--- a/runtime/indirect_reference_table_test.cc
+++ b/runtime/indirect_reference_table_test.cc
@@ -19,7 +19,7 @@
#include "class_linker-inl.h"
#include "common_runtime_test.h"
#include "mirror/object-inl.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
namespace art {
diff --git a/runtime/instrumentation_test.cc b/runtime/instrumentation_test.cc
index abe3184..7f9f04f 100644
--- a/runtime/instrumentation_test.cc
+++ b/runtime/instrumentation_test.cc
@@ -25,7 +25,7 @@
#include "handle_scope-inl.h"
#include "jvalue.h"
#include "runtime.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
#include "thread_list.h"
#include "thread-inl.h"
@@ -458,7 +458,7 @@
instrumentation::Instrumentation* instr = runtime->GetInstrumentation();
ClassLinker* class_linker = runtime->GetClassLinker();
StackHandleScope<1> hs(soa.Self());
- Handle<mirror::ClassLoader> loader(hs.NewHandle(soa.Decode<mirror::ClassLoader*>(class_loader)));
+ Handle<mirror::ClassLoader> loader(hs.NewHandle(soa.Decode<mirror::ClassLoader>(class_loader)));
mirror::Class* klass = class_linker->FindClass(soa.Self(), "LInstrumentation;", loader);
ASSERT_TRUE(klass != nullptr);
ArtMethod* method_to_deoptimize = klass->FindDeclaredDirectMethod("instanceMethod", "()V",
@@ -505,7 +505,7 @@
instrumentation::Instrumentation* instr = runtime->GetInstrumentation();
ClassLinker* class_linker = runtime->GetClassLinker();
StackHandleScope<1> hs(soa.Self());
- Handle<mirror::ClassLoader> loader(hs.NewHandle(soa.Decode<mirror::ClassLoader*>(class_loader)));
+ Handle<mirror::ClassLoader> loader(hs.NewHandle(soa.Decode<mirror::ClassLoader>(class_loader)));
mirror::Class* klass = class_linker->FindClass(soa.Self(), "LInstrumentation;", loader);
ASSERT_TRUE(klass != nullptr);
ArtMethod* method_to_deoptimize = klass->FindDeclaredDirectMethod("instanceMethod", "()V",
diff --git a/runtime/intern_table_test.cc b/runtime/intern_table_test.cc
index 620e15b..74cec57 100644
--- a/runtime/intern_table_test.cc
+++ b/runtime/intern_table_test.cc
@@ -20,7 +20,7 @@
#include "mirror/object.h"
#include "handle_scope-inl.h"
#include "mirror/string.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
namespace art {
diff --git a/runtime/interpreter/interpreter.cc b/runtime/interpreter/interpreter.cc
index 0003e72..c270df7 100644
--- a/runtime/interpreter/interpreter.cc
+++ b/runtime/interpreter/interpreter.cc
@@ -23,7 +23,7 @@
#include "interpreter_mterp_impl.h"
#include "interpreter_switch_impl.h"
#include "mirror/string-inl.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
#include "ScopedLocalRef.h"
#include "stack.h"
#include "unstarted_runtime.h"
@@ -51,7 +51,7 @@
ScopedThreadStateChange tsc(self, kNative);
jresult = fn(soa.Env(), klass.get());
}
- result->SetL(soa.Decode<Object*>(jresult));
+ result->SetL(soa.Decode<Object>(jresult).Decode());
} else if (shorty == "V") {
typedef void (fntype)(JNIEnv*, jclass);
fntype* const fn = reinterpret_cast<fntype*>(method->GetEntryPointFromJni());
@@ -93,7 +93,7 @@
ScopedThreadStateChange tsc(self, kNative);
jresult = fn(soa.Env(), klass.get(), arg0.get());
}
- result->SetL(soa.Decode<Object*>(jresult));
+ result->SetL(soa.Decode<Object>(jresult).Decode());
} else if (shorty == "IIZ") {
typedef jint (fntype)(JNIEnv*, jclass, jint, jboolean);
fntype* const fn = reinterpret_cast<fntype*>(method->GetEntryPointFromJni());
@@ -191,7 +191,7 @@
ScopedThreadStateChange tsc(self, kNative);
jresult = fn(soa.Env(), rcvr.get());
}
- result->SetL(soa.Decode<Object*>(jresult));
+ result->SetL(soa.Decode<Object>(jresult).Decode());
} else if (shorty == "V") {
typedef void (fntype)(JNIEnv*, jobject);
fntype* const fn = reinterpret_cast<fntype*>(method->GetEntryPointFromJni());
@@ -212,7 +212,7 @@
ScopedThreadStateChange tsc(self, kNative);
jresult = fn(soa.Env(), rcvr.get(), arg0.get());
}
- result->SetL(soa.Decode<Object*>(jresult));
+ result->SetL(soa.Decode<Object>(jresult).Decode());
ScopedThreadStateChange tsc(self, kNative);
} else if (shorty == "III") {
typedef jint (fntype)(JNIEnv*, jobject, jint, jint);
diff --git a/runtime/interpreter/interpreter_common.h b/runtime/interpreter/interpreter_common.h
index 814adf7..0feb013 100644
--- a/runtime/interpreter/interpreter_common.h
+++ b/runtime/interpreter/interpreter_common.h
@@ -254,9 +254,9 @@
DCHECK_LT(string_idx % mirror::DexCache::kDexCacheStringCacheSize,
declaring_class->GetDexFile().NumStringIds());
mirror::String* string_ptr =
- mirror::StringDexCachePair::LookupString(declaring_class->GetDexCacheStrings(),
- string_idx,
- mirror::DexCache::kDexCacheStringCacheSize).Read();
+ mirror::StringDexCachePair::Lookup(declaring_class->GetDexCacheStrings(),
+ string_idx,
+ mirror::DexCache::kDexCacheStringCacheSize).Read();
if (UNLIKELY(string_ptr == nullptr)) {
StackHandleScope<1> hs(self);
Handle<mirror::DexCache> dex_cache(hs.NewHandle(declaring_class->GetDexCache()));
diff --git a/runtime/interpreter/unstarted_runtime.cc b/runtime/interpreter/unstarted_runtime.cc
index 98e358b..39846da 100644
--- a/runtime/interpreter/unstarted_runtime.cc
+++ b/runtime/interpreter/unstarted_runtime.cc
@@ -1619,9 +1619,9 @@
uint32_t* args ATTRIBUTE_UNUSED, JValue* result) {
ScopedObjectAccessUnchecked soa(self);
if (Runtime::Current()->IsActiveTransaction()) {
- result->SetL(soa.Decode<mirror::Object*>(self->CreateInternalStackTrace<true>(soa)));
+ result->SetL(soa.Decode<mirror::Object>(self->CreateInternalStackTrace<true>(soa)).Decode());
} else {
- result->SetL(soa.Decode<mirror::Object*>(self->CreateInternalStackTrace<false>(soa)));
+ result->SetL(soa.Decode<mirror::Object>(self->CreateInternalStackTrace<false>(soa)).Decode());
}
}
diff --git a/runtime/interpreter/unstarted_runtime_test.cc b/runtime/interpreter/unstarted_runtime_test.cc
index ba751ec..6a4add3 100644
--- a/runtime/interpreter/unstarted_runtime_test.cc
+++ b/runtime/interpreter/unstarted_runtime_test.cc
@@ -31,7 +31,7 @@
#include "mirror/class_loader.h"
#include "mirror/string-inl.h"
#include "runtime.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
#include "thread.h"
#include "transaction.h"
diff --git a/runtime/java_vm_ext.cc b/runtime/java_vm_ext.cc
index 979495a..0c752ef 100644
--- a/runtime/java_vm_ext.cc
+++ b/runtime/java_vm_ext.cc
@@ -36,7 +36,7 @@
#include "runtime-inl.h"
#include "runtime_options.h"
#include "ScopedLocalRef.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
#include "thread-inl.h"
#include "thread_list.h"
@@ -532,17 +532,17 @@
return true;
}
-jobject JavaVMExt::AddGlobalRef(Thread* self, mirror::Object* obj) {
+jobject JavaVMExt::AddGlobalRef(Thread* self, ObjPtr<mirror::Object> obj) {
// Check for null after decoding the object to handle cleared weak globals.
if (obj == nullptr) {
return nullptr;
}
WriterMutexLock mu(self, globals_lock_);
- IndirectRef ref = globals_.Add(IRT_FIRST_SEGMENT, obj);
+ IndirectRef ref = globals_.Add(IRT_FIRST_SEGMENT, obj.Decode());
return reinterpret_cast<jobject>(ref);
}
-jweak JavaVMExt::AddWeakGlobalRef(Thread* self, mirror::Object* obj) {
+jweak JavaVMExt::AddWeakGlobalRef(Thread* self, ObjPtr<mirror::Object> obj) {
if (obj == nullptr) {
return nullptr;
}
@@ -550,7 +550,7 @@
while (UNLIKELY(!MayAccessWeakGlobals(self))) {
weak_globals_add_condition_.WaitHoldingLocks(self);
}
- IndirectRef ref = weak_globals_.Add(IRT_FIRST_SEGMENT, obj);
+ IndirectRef ref = weak_globals_.Add(IRT_FIRST_SEGMENT, obj.Decode());
return reinterpret_cast<jweak>(ref);
}
@@ -755,15 +755,15 @@
ScopedObjectAccess soa(env);
// As the incoming class loader is reachable/alive during the call of this function,
// it's okay to decode it without worrying about unexpectedly marking it alive.
- mirror::ClassLoader* loader = soa.Decode<mirror::ClassLoader*>(class_loader);
+ ObjPtr<mirror::ClassLoader> loader = soa.Decode<mirror::ClassLoader>(class_loader);
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
- if (class_linker->IsBootClassLoader(soa, loader)) {
+ if (class_linker->IsBootClassLoader(soa, loader.Decode())) {
loader = nullptr;
class_loader = nullptr;
}
- class_loader_allocator = class_linker->GetAllocatorForClassLoader(loader);
+ class_loader_allocator = class_linker->GetAllocatorForClassLoader(loader.Decode());
CHECK(class_loader_allocator != nullptr);
}
if (library != nullptr) {
diff --git a/runtime/java_vm_ext.h b/runtime/java_vm_ext.h
index a10a72f..558ffff 100644
--- a/runtime/java_vm_ext.h
+++ b/runtime/java_vm_ext.h
@@ -22,6 +22,7 @@
#include "base/macros.h"
#include "base/mutex.h"
#include "indirect_reference_table.h"
+#include "obj_ptr.h"
#include "reference_table.h"
namespace art {
@@ -123,10 +124,10 @@
void BroadcastForNewWeakGlobals() REQUIRES_SHARED(Locks::mutator_lock_)
REQUIRES(!weak_globals_lock_);
- jobject AddGlobalRef(Thread* self, mirror::Object* obj)
+ jobject AddGlobalRef(Thread* self, ObjPtr<mirror::Object> obj)
REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!globals_lock_);
- jweak AddWeakGlobalRef(Thread* self, mirror::Object* obj)
+ jweak AddWeakGlobalRef(Thread* self, ObjPtr<mirror::Object> obj)
REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!weak_globals_lock_);
void DeleteGlobalRef(Thread* self, jobject obj) REQUIRES(!globals_lock_);
diff --git a/runtime/jdwp/jdwp_event.cc b/runtime/jdwp/jdwp_event.cc
index e2d29fe..6aebe9f9 100644
--- a/runtime/jdwp/jdwp_event.cc
+++ b/runtime/jdwp/jdwp_event.cc
@@ -30,7 +30,7 @@
#include "jdwp/jdwp_expand_buf.h"
#include "jdwp/jdwp_priv.h"
#include "jdwp/object_registry.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
#include "thread-inl.h"
#include "handle_scope-inl.h"
diff --git a/runtime/jdwp/jdwp_handler.cc b/runtime/jdwp/jdwp_handler.cc
index f6008ac..0f2d188 100644
--- a/runtime/jdwp/jdwp_handler.cc
+++ b/runtime/jdwp/jdwp_handler.cc
@@ -31,7 +31,7 @@
#include "jdwp/jdwp_expand_buf.h"
#include "jdwp/jdwp_priv.h"
#include "runtime.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
#include "thread-inl.h"
#include "utils.h"
diff --git a/runtime/jdwp/jdwp_main.cc b/runtime/jdwp/jdwp_main.cc
index dbf04fe..e3bf3e5 100644
--- a/runtime/jdwp/jdwp_main.cc
+++ b/runtime/jdwp/jdwp_main.cc
@@ -25,7 +25,7 @@
#include "base/time_utils.h"
#include "debugger.h"
#include "jdwp/jdwp_priv.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
namespace art {
diff --git a/runtime/jdwp/object_registry.cc b/runtime/jdwp/object_registry.cc
index 5989b61..9ba62c9 100644
--- a/runtime/jdwp/object_registry.cc
+++ b/runtime/jdwp/object_registry.cc
@@ -19,7 +19,7 @@
#include "handle_scope-inl.h"
#include "jni_internal.h"
#include "mirror/class.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
namespace art {
diff --git a/runtime/jit/jit_code_cache.cc b/runtime/jit/jit_code_cache.cc
index c9227b1..2c6b249 100644
--- a/runtime/jit/jit_code_cache.cc
+++ b/runtime/jit/jit_code_cache.cc
@@ -32,7 +32,7 @@
#include "linear_alloc.h"
#include "mem_map.h"
#include "oat_file-inl.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
#include "thread_list.h"
namespace art {
diff --git a/runtime/jit/profile_compilation_info_test.cc b/runtime/jit/profile_compilation_info_test.cc
index c8f4d94..764458a 100644
--- a/runtime/jit/profile_compilation_info_test.cc
+++ b/runtime/jit/profile_compilation_info_test.cc
@@ -26,7 +26,7 @@
#include "mirror/class_loader.h"
#include "handle_scope-inl.h"
#include "jit/offline_profiling_info.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
namespace art {
diff --git a/runtime/jit/profile_saver.cc b/runtime/jit/profile_saver.cc
index a4bc3fc..d23821b 100644
--- a/runtime/jit/profile_saver.cc
+++ b/runtime/jit/profile_saver.cc
@@ -26,7 +26,7 @@
#include "base/time_utils.h"
#include "compiler_filter.h"
#include "oat_file_manager.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
namespace art {
diff --git a/runtime/jit/profiling_info.cc b/runtime/jit/profiling_info.cc
index 216df2f..6ba187e 100644
--- a/runtime/jit/profiling_info.cc
+++ b/runtime/jit/profiling_info.cc
@@ -20,7 +20,7 @@
#include "dex_instruction.h"
#include "jit/jit.h"
#include "jit/jit_code_cache.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
#include "thread.h"
namespace art {
diff --git a/runtime/jni_internal.cc b/runtime/jni_internal.cc
index a11f9ab..7b27578 100644
--- a/runtime/jni_internal.cc
+++ b/runtime/jni_internal.cc
@@ -52,7 +52,7 @@
#include "reflection.h"
#include "runtime.h"
#include "safe_map.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
#include "ScopedLocalRef.h"
#include "thread.h"
#include "utf.h"
@@ -108,7 +108,7 @@
"%s is null at index %d", kind, idx);
}
-static mirror::Class* EnsureInitialized(Thread* self, mirror::Class* klass)
+static ObjPtr<mirror::Class> EnsureInitialized(Thread* self, ObjPtr<mirror::Class> klass)
REQUIRES_SHARED(Locks::mutator_lock_) {
if (LIKELY(klass->IsInitialized())) {
return klass;
@@ -124,7 +124,7 @@
static jmethodID FindMethodID(ScopedObjectAccess& soa, jclass jni_class,
const char* name, const char* sig, bool is_static)
REQUIRES_SHARED(Locks::mutator_lock_) {
- mirror::Class* c = EnsureInitialized(soa.Self(), soa.Decode<mirror::Class*>(jni_class));
+ ObjPtr<mirror::Class> c = EnsureInitialized(soa.Self(), soa.Decode<mirror::Class>(jni_class));
if (c == nullptr) {
return nullptr;
}
@@ -143,31 +143,31 @@
}
}
if (method == nullptr || method->IsStatic() != is_static) {
- ThrowNoSuchMethodError(soa, c, name, sig, is_static ? "static" : "non-static");
+ ThrowNoSuchMethodError(soa, c.Decode(), name, sig, is_static ? "static" : "non-static");
return nullptr;
}
return soa.EncodeMethod(method);
}
-static mirror::ClassLoader* GetClassLoader(const ScopedObjectAccess& soa)
+static ObjPtr<mirror::ClassLoader> GetClassLoader(const ScopedObjectAccess& soa)
REQUIRES_SHARED(Locks::mutator_lock_) {
ArtMethod* method = soa.Self()->GetCurrentMethod(nullptr);
// If we are running Runtime.nativeLoad, use the overriding ClassLoader it set.
if (method == soa.DecodeMethod(WellKnownClasses::java_lang_Runtime_nativeLoad)) {
- return soa.Decode<mirror::ClassLoader*>(soa.Self()->GetClassLoaderOverride());
+ return soa.Decode<mirror::ClassLoader>(soa.Self()->GetClassLoaderOverride());
}
// If we have a method, use its ClassLoader for context.
if (method != nullptr) {
return method->GetDeclaringClass()->GetClassLoader();
}
// We don't have a method, so try to use the system ClassLoader.
- mirror::ClassLoader* class_loader =
- soa.Decode<mirror::ClassLoader*>(Runtime::Current()->GetSystemClassLoader());
+ ObjPtr<mirror::ClassLoader> class_loader =
+ soa.Decode<mirror::ClassLoader>(Runtime::Current()->GetSystemClassLoader());
if (class_loader != nullptr) {
return class_loader;
}
// See if the override ClassLoader is set for gtests.
- class_loader = soa.Decode<mirror::ClassLoader*>(soa.Self()->GetClassLoaderOverride());
+ class_loader = soa.Decode<mirror::ClassLoader>(soa.Self()->GetClassLoaderOverride());
if (class_loader != nullptr) {
// If so, CommonCompilerTest should have marked the runtime as a compiler not compiling an
// image.
@@ -184,7 +184,7 @@
REQUIRES_SHARED(Locks::mutator_lock_) {
StackHandleScope<2> hs(soa.Self());
Handle<mirror::Class> c(
- hs.NewHandle(EnsureInitialized(soa.Self(), soa.Decode<mirror::Class*>(jni_class))));
+ hs.NewHandle(EnsureInitialized(soa.Self(), soa.Decode<mirror::Class>(jni_class))));
if (c.Get() == nullptr) {
return nullptr;
}
@@ -272,7 +272,7 @@
if (mid == nullptr) {
ScopedObjectAccess soa(env);
LOG(ERROR) << "No <init>" << signature << " in "
- << PrettyClass(soa.Decode<mirror::Class*>(exception_class));
+ << PrettyClass(soa.Decode<mirror::Class>(exception_class));
return JNI_ERR;
}
@@ -282,7 +282,7 @@
return JNI_ERR;
}
ScopedObjectAccess soa(env);
- soa.Self()->SetException(soa.Decode<mirror::Throwable*>(exception.get()));
+ soa.Self()->SetException(soa.Decode<mirror::Throwable>(exception.get()).Decode());
return JNI_OK;
}
@@ -363,12 +363,12 @@
static jfieldID FromReflectedField(JNIEnv* env, jobject jlr_field) {
CHECK_NON_NULL_ARGUMENT(jlr_field);
ScopedObjectAccess soa(env);
- mirror::Object* obj_field = soa.Decode<mirror::Object*>(jlr_field);
+ ObjPtr<mirror::Object> obj_field = soa.Decode<mirror::Object>(jlr_field);
if (obj_field->GetClass() != mirror::Field::StaticClass()) {
// Not even a java.lang.reflect.Field, return null. TODO, is this check necessary?
return nullptr;
}
- auto* field = static_cast<mirror::Field*>(obj_field);
+ ObjPtr<mirror::Field> field = down_cast<mirror::Field*>(obj_field.Decode());
return soa.EncodeField(field->GetArtField());
}
@@ -398,14 +398,14 @@
static jclass GetObjectClass(JNIEnv* env, jobject java_object) {
CHECK_NON_NULL_ARGUMENT(java_object);
ScopedObjectAccess soa(env);
- mirror::Object* o = soa.Decode<mirror::Object*>(java_object);
+ ObjPtr<mirror::Object> o = soa.Decode<mirror::Object>(java_object);
return soa.AddLocalReference<jclass>(o->GetClass());
}
static jclass GetSuperclass(JNIEnv* env, jclass java_class) {
CHECK_NON_NULL_ARGUMENT(java_class);
ScopedObjectAccess soa(env);
- mirror::Class* c = soa.Decode<mirror::Class*>(java_class);
+ ObjPtr<mirror::Class> c = soa.Decode<mirror::Class>(java_class);
return soa.AddLocalReference<jclass>(c->IsInterface() ? nullptr : c->GetSuperClass());
}
@@ -415,9 +415,9 @@
CHECK_NON_NULL_ARGUMENT_RETURN(java_class1, JNI_FALSE);
CHECK_NON_NULL_ARGUMENT_RETURN(java_class2, JNI_FALSE);
ScopedObjectAccess soa(env);
- mirror::Class* c1 = soa.Decode<mirror::Class*>(java_class1);
- mirror::Class* c2 = soa.Decode<mirror::Class*>(java_class2);
- return c2->IsAssignableFrom(c1) ? JNI_TRUE : JNI_FALSE;
+ ObjPtr<mirror::Class> c1 = soa.Decode<mirror::Class>(java_class1);
+ ObjPtr<mirror::Class> c2 = soa.Decode<mirror::Class>(java_class2);
+ return c2->IsAssignableFrom(c1.Decode()) ? JNI_TRUE : JNI_FALSE;
}
static jboolean IsInstanceOf(JNIEnv* env, jobject jobj, jclass java_class) {
@@ -427,19 +427,19 @@
return JNI_TRUE;
} else {
ScopedObjectAccess soa(env);
- mirror::Object* obj = soa.Decode<mirror::Object*>(jobj);
- mirror::Class* c = soa.Decode<mirror::Class*>(java_class);
+ ObjPtr<mirror::Object> obj = soa.Decode<mirror::Object>(jobj);
+ ObjPtr<mirror::Class> c = soa.Decode<mirror::Class>(java_class);
return obj->InstanceOf(c) ? JNI_TRUE : JNI_FALSE;
}
}
static jint Throw(JNIEnv* env, jthrowable java_exception) {
ScopedObjectAccess soa(env);
- mirror::Throwable* exception = soa.Decode<mirror::Throwable*>(java_exception);
+ ObjPtr<mirror::Throwable> exception = soa.Decode<mirror::Throwable>(java_exception);
if (exception == nullptr) {
return JNI_ERR;
}
- soa.Self()->SetException(exception);
+ soa.Self()->SetException(exception.Decode());
return JNI_OK;
}
@@ -509,7 +509,7 @@
static jobject PopLocalFrame(JNIEnv* env, jobject java_survivor) {
ScopedObjectAccess soa(env);
- mirror::Object* survivor = soa.Decode<mirror::Object*>(java_survivor);
+ ObjPtr<mirror::Object> survivor = soa.Decode<mirror::Object>(java_survivor);
soa.Env()->PopFrame();
return soa.AddLocalReference<jobject>(survivor);
}
@@ -522,8 +522,8 @@
static jobject NewGlobalRef(JNIEnv* env, jobject obj) {
ScopedObjectAccess soa(env);
- mirror::Object* decoded_obj = soa.Decode<mirror::Object*>(obj);
- return soa.Vm()->AddGlobalRef(soa.Self(), decoded_obj);
+ ObjPtr<mirror::Object> decoded_obj = soa.Decode<mirror::Object>(obj);
+ return soa.Vm()->AddGlobalRef(soa.Self(), decoded_obj.Decode());
}
static void DeleteGlobalRef(JNIEnv* env, jobject obj) {
@@ -534,8 +534,8 @@
static jweak NewWeakGlobalRef(JNIEnv* env, jobject obj) {
ScopedObjectAccess soa(env);
- mirror::Object* decoded_obj = soa.Decode<mirror::Object*>(obj);
- return soa.Vm()->AddWeakGlobalRef(soa.Self(), decoded_obj);
+ ObjPtr<mirror::Object> decoded_obj = soa.Decode<mirror::Object>(obj);
+ return soa.Vm()->AddWeakGlobalRef(soa.Self(), decoded_obj.Decode());
}
static void DeleteWeakGlobalRef(JNIEnv* env, jweak obj) {
@@ -546,7 +546,7 @@
static jobject NewLocalRef(JNIEnv* env, jobject obj) {
ScopedObjectAccess soa(env);
- mirror::Object* decoded_obj = soa.Decode<mirror::Object*>(obj);
+ ObjPtr<mirror::Object> decoded_obj = soa.Decode<mirror::Object>(obj);
// Check for null after decoding the object to handle cleared weak globals.
if (decoded_obj == nullptr) {
return nullptr;
@@ -579,7 +579,7 @@
return JNI_TRUE;
} else {
ScopedObjectAccess soa(env);
- return (soa.Decode<mirror::Object*>(obj1) == soa.Decode<mirror::Object*>(obj2))
+ return (soa.Decode<mirror::Object>(obj1) == soa.Decode<mirror::Object>(obj2))
? JNI_TRUE : JNI_FALSE;
}
}
@@ -587,7 +587,7 @@
static jobject AllocObject(JNIEnv* env, jclass java_class) {
CHECK_NON_NULL_ARGUMENT(java_class);
ScopedObjectAccess soa(env);
- mirror::Class* c = EnsureInitialized(soa.Self(), soa.Decode<mirror::Class*>(java_class));
+ ObjPtr<mirror::Class> c = EnsureInitialized(soa.Self(), soa.Decode<mirror::Class>(java_class));
if (c == nullptr) {
return nullptr;
}
@@ -613,7 +613,8 @@
CHECK_NON_NULL_ARGUMENT(java_class);
CHECK_NON_NULL_ARGUMENT(mid);
ScopedObjectAccess soa(env);
- mirror::Class* c = EnsureInitialized(soa.Self(), soa.Decode<mirror::Class*>(java_class));
+ ObjPtr<mirror::Class> c = EnsureInitialized(soa.Self(),
+ soa.Decode<mirror::Class>(java_class));
if (c == nullptr) {
return nullptr;
}
@@ -639,7 +640,8 @@
CHECK_NON_NULL_ARGUMENT(java_class);
CHECK_NON_NULL_ARGUMENT(mid);
ScopedObjectAccess soa(env);
- mirror::Class* c = EnsureInitialized(soa.Self(), soa.Decode<mirror::Class*>(java_class));
+ ObjPtr<mirror::Class> c = EnsureInitialized(soa.Self(),
+ soa.Decode<mirror::Class>(java_class));
if (c == nullptr) {
return nullptr;
}
@@ -1223,9 +1225,9 @@
CHECK_NON_NULL_ARGUMENT(obj);
CHECK_NON_NULL_ARGUMENT(fid);
ScopedObjectAccess soa(env);
- mirror::Object* o = soa.Decode<mirror::Object*>(obj);
+ ObjPtr<mirror::Object> o = soa.Decode<mirror::Object>(obj);
ArtField* f = soa.DecodeField(fid);
- return soa.AddLocalReference<jobject>(f->GetObject(o));
+ return soa.AddLocalReference<jobject>(f->GetObject(o.Decode()));
}
static jobject GetStaticObjectField(JNIEnv* env, jclass, jfieldID fid) {
@@ -1239,27 +1241,27 @@
CHECK_NON_NULL_ARGUMENT_RETURN_VOID(java_object);
CHECK_NON_NULL_ARGUMENT_RETURN_VOID(fid);
ScopedObjectAccess soa(env);
- mirror::Object* o = soa.Decode<mirror::Object*>(java_object);
- mirror::Object* v = soa.Decode<mirror::Object*>(java_value);
+ ObjPtr<mirror::Object> o = soa.Decode<mirror::Object>(java_object);
+ ObjPtr<mirror::Object> v = soa.Decode<mirror::Object>(java_value);
ArtField* f = soa.DecodeField(fid);
- f->SetObject<false>(o, v);
+ f->SetObject<false>(o.Decode(), v.Decode());
}
static void SetStaticObjectField(JNIEnv* env, jclass, jfieldID fid, jobject java_value) {
CHECK_NON_NULL_ARGUMENT_RETURN_VOID(fid);
ScopedObjectAccess soa(env);
- mirror::Object* v = soa.Decode<mirror::Object*>(java_value);
+ ObjPtr<mirror::Object> v = soa.Decode<mirror::Object>(java_value);
ArtField* f = soa.DecodeField(fid);
- f->SetObject<false>(f->GetDeclaringClass(), v);
+ f->SetObject<false>(f->GetDeclaringClass(), v.Decode());
}
#define GET_PRIMITIVE_FIELD(fn, instance) \
CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(instance); \
CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(fid); \
ScopedObjectAccess soa(env); \
- mirror::Object* o = soa.Decode<mirror::Object*>(instance); \
+ ObjPtr<mirror::Object> o = soa.Decode<mirror::Object>(instance); \
ArtField* f = soa.DecodeField(fid); \
- return f->Get ##fn (o)
+ return f->Get ##fn (o.Decode())
#define GET_STATIC_PRIMITIVE_FIELD(fn) \
CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(fid); \
@@ -1271,9 +1273,9 @@
CHECK_NON_NULL_ARGUMENT_RETURN_VOID(instance); \
CHECK_NON_NULL_ARGUMENT_RETURN_VOID(fid); \
ScopedObjectAccess soa(env); \
- mirror::Object* o = soa.Decode<mirror::Object*>(instance); \
+ ObjPtr<mirror::Object> o = soa.Decode<mirror::Object>(instance); \
ArtField* f = soa.DecodeField(fid); \
- f->Set ##fn <false>(o, value)
+ f->Set ##fn <false>(o.Decode(), value)
#define SET_STATIC_PRIMITIVE_FIELD(fn, value) \
CHECK_NON_NULL_ARGUMENT_RETURN_VOID(fid); \
@@ -1657,20 +1659,20 @@
static jsize GetStringLength(JNIEnv* env, jstring java_string) {
CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(java_string);
ScopedObjectAccess soa(env);
- return soa.Decode<mirror::String*>(java_string)->GetLength();
+ return soa.Decode<mirror::String>(java_string)->GetLength();
}
static jsize GetStringUTFLength(JNIEnv* env, jstring java_string) {
CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(java_string);
ScopedObjectAccess soa(env);
- return soa.Decode<mirror::String*>(java_string)->GetUtfLength();
+ return soa.Decode<mirror::String>(java_string)->GetUtfLength();
}
static void GetStringRegion(JNIEnv* env, jstring java_string, jsize start, jsize length,
jchar* buf) {
CHECK_NON_NULL_ARGUMENT_RETURN_VOID(java_string);
ScopedObjectAccess soa(env);
- mirror::String* s = soa.Decode<mirror::String*>(java_string);
+ ObjPtr<mirror::String> s = soa.Decode<mirror::String>(java_string);
if (start < 0 || length < 0 || length > s->GetLength() - start) {
ThrowSIOOBE(soa, start, length, s->GetLength());
} else {
@@ -1690,7 +1692,7 @@
char* buf) {
CHECK_NON_NULL_ARGUMENT_RETURN_VOID(java_string);
ScopedObjectAccess soa(env);
- mirror::String* s = soa.Decode<mirror::String*>(java_string);
+ ObjPtr<mirror::String> s = soa.Decode<mirror::String>(java_string);
if (start < 0 || length < 0 || length > s->GetLength() - start) {
ThrowSIOOBE(soa, start, length, s->GetLength());
} else {
@@ -1710,7 +1712,7 @@
static const jchar* GetStringChars(JNIEnv* env, jstring java_string, jboolean* is_copy) {
CHECK_NON_NULL_ARGUMENT(java_string);
ScopedObjectAccess soa(env);
- mirror::String* s = soa.Decode<mirror::String*>(java_string);
+ ObjPtr<mirror::String> s = soa.Decode<mirror::String>(java_string);
gc::Heap* heap = Runtime::Current()->GetHeap();
if (heap->IsMovableObject(s) || s->IsCompressed()) {
jchar* chars = new jchar[s->GetLength()];
@@ -1736,7 +1738,7 @@
static void ReleaseStringChars(JNIEnv* env, jstring java_string, const jchar* chars) {
CHECK_NON_NULL_ARGUMENT_RETURN_VOID(java_string);
ScopedObjectAccess soa(env);
- mirror::String* s = soa.Decode<mirror::String*>(java_string);
+ ObjPtr<mirror::String> s = soa.Decode<mirror::String>(java_string);
if (s->IsCompressed() || (s->IsCompressed() == false && chars != s->GetValue())) {
delete[] chars;
}
@@ -1745,11 +1747,11 @@
static const jchar* GetStringCritical(JNIEnv* env, jstring java_string, jboolean* is_copy) {
CHECK_NON_NULL_ARGUMENT(java_string);
ScopedObjectAccess soa(env);
- mirror::String* s = soa.Decode<mirror::String*>(java_string);
+ ObjPtr<mirror::String> s = soa.Decode<mirror::String>(java_string);
gc::Heap* heap = Runtime::Current()->GetHeap();
if (heap->IsMovableObject(s)) {
StackHandleScope<1> hs(soa.Self());
- HandleWrapper<mirror::String> h(hs.NewHandleWrapper(&s));
+ HandleWrapperObjPtr<mirror::String> h(hs.NewHandleWrapper(&s));
if (!kUseReadBarrier) {
heap->IncrementDisableMovingGC(soa.Self());
} else {
@@ -1782,7 +1784,7 @@
CHECK_NON_NULL_ARGUMENT_RETURN_VOID(java_string);
ScopedObjectAccess soa(env);
gc::Heap* heap = Runtime::Current()->GetHeap();
- mirror::String* s = soa.Decode<mirror::String*>(java_string);
+ ObjPtr<mirror::String> s = soa.Decode<mirror::String>(java_string);
if (heap->IsMovableObject(s)) {
if (!kUseReadBarrier) {
heap->DecrementDisableMovingGC(soa.Self());
@@ -1803,7 +1805,7 @@
*is_copy = JNI_TRUE;
}
ScopedObjectAccess soa(env);
- mirror::String* s = soa.Decode<mirror::String*>(java_string);
+ ObjPtr<mirror::String> s = soa.Decode<mirror::String>(java_string);
size_t byte_count = s->GetUtfLength();
char* bytes = new char[byte_count + 1];
CHECK(bytes != nullptr); // bionic aborts anyway.
@@ -1826,7 +1828,7 @@
static jsize GetArrayLength(JNIEnv* env, jarray java_array) {
CHECK_NON_NULL_ARGUMENT_RETURN_ZERO(java_array);
ScopedObjectAccess soa(env);
- mirror::Object* obj = soa.Decode<mirror::Object*>(java_array);
+ ObjPtr<mirror::Object> obj = soa.Decode<mirror::Object>(java_array);
if (UNLIKELY(!obj->IsArrayInstance())) {
soa.Vm()->JniAbortF("GetArrayLength", "not an array: %s", PrettyTypeOf(obj).c_str());
return 0;
@@ -1838,8 +1840,8 @@
static jobject GetObjectArrayElement(JNIEnv* env, jobjectArray java_array, jsize index) {
CHECK_NON_NULL_ARGUMENT(java_array);
ScopedObjectAccess soa(env);
- mirror::ObjectArray<mirror::Object>* array =
- soa.Decode<mirror::ObjectArray<mirror::Object>*>(java_array);
+ ObjPtr<mirror::ObjectArray<mirror::Object>> array =
+ soa.Decode<mirror::ObjectArray<mirror::Object>>(java_array);
return soa.AddLocalReference<jobject>(array->Get(index));
}
@@ -1847,10 +1849,10 @@
jobject java_value) {
CHECK_NON_NULL_ARGUMENT_RETURN_VOID(java_array);
ScopedObjectAccess soa(env);
- mirror::ObjectArray<mirror::Object>* array =
- soa.Decode<mirror::ObjectArray<mirror::Object>*>(java_array);
- mirror::Object* value = soa.Decode<mirror::Object*>(java_value);
- array->Set<false>(index, value);
+ ObjPtr<mirror::ObjectArray<mirror::Object>> array =
+ soa.Decode<mirror::ObjectArray<mirror::Object>>(java_array);
+ ObjPtr<mirror::Object> value = soa.Decode<mirror::Object>(java_value);
+ array->Set<false>(index, value.Decode());
}
static jbooleanArray NewBooleanArray(JNIEnv* env, jsize length) {
@@ -1893,7 +1895,7 @@
ScopedObjectAccess soa(env);
mirror::Class* array_class;
{
- mirror::Class* element_class = soa.Decode<mirror::Class*>(element_jclass);
+ mirror::Class* element_class = soa.Decode<mirror::Class>(element_jclass).Decode();
if (UNLIKELY(element_class->IsPrimitive())) {
soa.Vm()->JniAbortF("NewObjectArray", "not an object type: %s",
PrettyDescriptor(element_class).c_str());
@@ -1910,7 +1912,7 @@
mirror::ObjectArray<mirror::Object>* result =
mirror::ObjectArray<mirror::Object>::Alloc(soa.Self(), array_class, length);
if (result != nullptr && initial_element != nullptr) {
- mirror::Object* initial_object = soa.Decode<mirror::Object*>(initial_element);
+ ObjPtr<mirror::Object> initial_object = soa.Decode<mirror::Object>(initial_element);
if (initial_object != nullptr) {
mirror::Class* element_class = result->GetClass()->GetComponentType();
if (UNLIKELY(!element_class->IsAssignableFrom(initial_object->GetClass()))) {
@@ -1921,7 +1923,7 @@
return nullptr;
} else {
for (jsize i = 0; i < length; ++i) {
- result->SetWithoutChecks<false>(i, initial_object);
+ result->SetWithoutChecks<false>(i, initial_object.Decode());
}
}
}
@@ -1936,7 +1938,7 @@
static void* GetPrimitiveArrayCritical(JNIEnv* env, jarray java_array, jboolean* is_copy) {
CHECK_NON_NULL_ARGUMENT(java_array);
ScopedObjectAccess soa(env);
- mirror::Array* array = soa.Decode<mirror::Array*>(java_array);
+ ObjPtr<mirror::Array> array = soa.Decode<mirror::Array>(java_array);
if (UNLIKELY(!array->GetClass()->IsPrimitiveArray())) {
soa.Vm()->JniAbortF("GetPrimitiveArrayCritical", "expected primitive array, given %s",
PrettyDescriptor(array->GetClass()).c_str());
@@ -1952,7 +1954,7 @@
heap->IncrementDisableThreadFlip(soa.Self());
}
// Re-decode in case the object moved since IncrementDisableGC waits for GC to complete.
- array = soa.Decode<mirror::Array*>(java_array);
+ array = soa.Decode<mirror::Array>(java_array);
}
if (is_copy != nullptr) {
*is_copy = JNI_FALSE;
@@ -1964,14 +1966,14 @@
jint mode) {
CHECK_NON_NULL_ARGUMENT_RETURN_VOID(java_array);
ScopedObjectAccess soa(env);
- mirror::Array* array = soa.Decode<mirror::Array*>(java_array);
+ ObjPtr<mirror::Array> array = soa.Decode<mirror::Array>(java_array);
if (UNLIKELY(!array->GetClass()->IsPrimitiveArray())) {
soa.Vm()->JniAbortF("ReleasePrimitiveArrayCritical", "expected primitive array, given %s",
PrettyDescriptor(array->GetClass()).c_str());
return;
}
const size_t component_size = array->GetClass()->GetComponentSize();
- ReleasePrimitiveArray(soa, array, component_size, elements, mode);
+ ReleasePrimitiveArray(soa, array.Decode(), component_size, elements, mode);
}
static jboolean* GetBooleanArrayElements(JNIEnv* env, jbooleanArray array, jboolean* is_copy) {
@@ -2145,7 +2147,7 @@
}
CHECK_NON_NULL_ARGUMENT_FN_NAME("RegisterNatives", java_class, JNI_ERR);
ScopedObjectAccess soa(env);
- mirror::Class* c = soa.Decode<mirror::Class*>(java_class);
+ ObjPtr<mirror::Class> c = soa.Decode<mirror::Class>(java_class);
if (UNLIKELY(method_count == 0)) {
LOG(WARNING) << "JNI RegisterNativeMethods: attempt to register 0 native methods for "
<< PrettyDescriptor(c);
@@ -2157,13 +2159,13 @@
const char* sig = methods[i].signature;
const void* fnPtr = methods[i].fnPtr;
if (UNLIKELY(name == nullptr)) {
- ReportInvalidJNINativeMethod(soa, c, "method name", i, return_errors);
+ ReportInvalidJNINativeMethod(soa, c.Decode(), "method name", i, return_errors);
return JNI_ERR;
} else if (UNLIKELY(sig == nullptr)) {
- ReportInvalidJNINativeMethod(soa, c, "method signature", i, return_errors);
+ ReportInvalidJNINativeMethod(soa, c.Decode(), "method signature", i, return_errors);
return JNI_ERR;
} else if (UNLIKELY(fnPtr == nullptr)) {
- ReportInvalidJNINativeMethod(soa, c, "native function", i, return_errors);
+ ReportInvalidJNINativeMethod(soa, c.Decode(), "native function", i, return_errors);
return JNI_ERR;
}
bool is_fast = false;
@@ -2206,17 +2208,17 @@
// the parent.
ArtMethod* m = nullptr;
bool warn_on_going_to_parent = down_cast<JNIEnvExt*>(env)->vm->IsCheckJniEnabled();
- for (mirror::Class* current_class = c;
+ for (ObjPtr<mirror::Class> current_class = c;
current_class != nullptr;
current_class = current_class->GetSuperClass()) {
// Search first only comparing methods which are native.
- m = FindMethod<true>(current_class, name, sig);
+ m = FindMethod<true>(current_class.Decode(), name, sig);
if (m != nullptr) {
break;
}
// Search again comparing to all methods, to find non-native methods that match.
- m = FindMethod<false>(current_class, name, sig);
+ m = FindMethod<false>(current_class.Decode(), name, sig);
if (m != nullptr) {
break;
}
@@ -2238,14 +2240,14 @@
<< "Failed to register native method "
<< PrettyDescriptor(c) << "." << name << sig << " in "
<< c->GetDexCache()->GetLocation()->ToModifiedUtf8();
- ThrowNoSuchMethodError(soa, c, name, sig, "static or non-static");
+ ThrowNoSuchMethodError(soa, c.Decode(), name, sig, "static or non-static");
return JNI_ERR;
} else if (!m->IsNative()) {
LOG(return_errors ? ::android::base::ERROR : ::android::base::FATAL)
<< "Failed to register non-native method "
<< PrettyDescriptor(c) << "." << name << sig
<< " as native";
- ThrowNoSuchMethodError(soa, c, name, sig, "native");
+ ThrowNoSuchMethodError(soa, c.Decode(), name, sig, "native");
return JNI_ERR;
}
@@ -2260,7 +2262,7 @@
static jint UnregisterNatives(JNIEnv* env, jclass java_class) {
CHECK_NON_NULL_ARGUMENT_RETURN(java_class, JNI_ERR);
ScopedObjectAccess soa(env);
- mirror::Class* c = soa.Decode<mirror::Class*>(java_class);
+ ObjPtr<mirror::Class> c = soa.Decode<mirror::Class>(java_class);
VLOG(jni) << "[Unregistering JNI native methods for " << PrettyClass(c) << "]";
@@ -2283,24 +2285,24 @@
static jint MonitorEnter(JNIEnv* env, jobject java_object) NO_THREAD_SAFETY_ANALYSIS {
CHECK_NON_NULL_ARGUMENT_RETURN(java_object, JNI_ERR);
ScopedObjectAccess soa(env);
- mirror::Object* o = soa.Decode<mirror::Object*>(java_object);
+ ObjPtr<mirror::Object> o = soa.Decode<mirror::Object>(java_object);
o = o->MonitorEnter(soa.Self());
if (soa.Self()->IsExceptionPending()) {
return JNI_ERR;
}
- soa.Env()->monitors.Add(o);
+ soa.Env()->monitors.Add(o.Decode());
return JNI_OK;
}
static jint MonitorExit(JNIEnv* env, jobject java_object) NO_THREAD_SAFETY_ANALYSIS {
CHECK_NON_NULL_ARGUMENT_RETURN(java_object, JNI_ERR);
ScopedObjectAccess soa(env);
- mirror::Object* o = soa.Decode<mirror::Object*>(java_object);
+ ObjPtr<mirror::Object> o = soa.Decode<mirror::Object>(java_object);
o->MonitorExit(soa.Self());
if (soa.Self()->IsExceptionPending()) {
return JNI_ERR;
}
- soa.Env()->monitors.Remove(o);
+ soa.Env()->monitors.Remove(o.Decode());
return JNI_OK;
}
@@ -2409,7 +2411,7 @@
static ArtArrayT* DecodeAndCheckArrayType(ScopedObjectAccess& soa, JArrayT java_array,
const char* fn_name, const char* operation)
REQUIRES_SHARED(Locks::mutator_lock_) {
- ArtArrayT* array = soa.Decode<ArtArrayT*>(java_array);
+ ObjPtr<ArtArrayT> array = soa.Decode<ArtArrayT>(java_array);
if (UNLIKELY(ArtArrayT::GetArrayClass() != array->GetClass())) {
soa.Vm()->JniAbortF(fn_name,
"attempt to %s %s primitive array elements with an object of type %s",
@@ -2419,7 +2421,7 @@
return nullptr;
}
DCHECK_EQ(sizeof(ElementT), array->GetClass()->GetComponentSize());
- return array;
+ return array.Decode();
}
template <typename ArrayT, typename ElementT, typename ArtArrayT>
diff --git a/runtime/jni_internal_test.cc b/runtime/jni_internal_test.cc
index fe0081c..fbd670c 100644
--- a/runtime/jni_internal_test.cc
+++ b/runtime/jni_internal_test.cc
@@ -22,7 +22,7 @@
#include "java_vm_ext.h"
#include "jni_env_ext.h"
#include "mirror/string-inl.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
#include "ScopedLocalRef.h"
namespace art {
@@ -58,7 +58,7 @@
void ExpectException(jclass exception_class) {
ScopedObjectAccess soa(env_);
EXPECT_TRUE(env_->ExceptionCheck())
- << PrettyDescriptor(soa.Decode<mirror::Class*>(exception_class));
+ << PrettyDescriptor(soa.Decode<mirror::Class>(exception_class));
jthrowable exception = env_->ExceptionOccurred();
EXPECT_NE(nullptr, exception);
env_->ExceptionClear();
@@ -619,7 +619,7 @@
class_loader_ = LoadDex("MyClassNatives");
StackHandleScope<1> hs(soa.Self());
Handle<mirror::ClassLoader> loader(
- hs.NewHandle(soa.Decode<mirror::ClassLoader*>(class_loader_)));
+ hs.NewHandle(soa.Decode<mirror::ClassLoader>(class_loader_)));
mirror::Class* c = class_linker_->FindClass(soa.Self(), "LMyClassNatives;", loader);
const auto pointer_size = class_linker_->GetImagePointerSize();
ArtMethod* method = direct ? c->FindDirectMethod(method_name, method_sig, pointer_size) :
@@ -679,7 +679,12 @@
ASSERT_TRUE(env_->IsInstanceOf(o, c));
// ...whose fields haven't been initialized because
// we didn't call a constructor.
- ASSERT_EQ(0, env_->GetIntField(o, env_->GetFieldID(c, "count", "I")));
+ if (art::mirror::kUseStringCompression) {
+ // Zero-length string is compressed, so the length internally will be -(1 << 31).
+ ASSERT_EQ(-2147483648, env_->GetIntField(o, env_->GetFieldID(c, "count", "I")));
+ } else {
+ ASSERT_EQ(0, env_->GetIntField(o, env_->GetFieldID(c, "count", "I")));
+ }
}
TEST_F(JniInternalTest, GetVersion) {
@@ -1598,7 +1603,7 @@
TEST_F(JniInternalTest, GetStringChars_ReleaseStringChars) {
jstring s = env_->NewStringUTF("hello");
ScopedObjectAccess soa(env_);
- mirror::String* s_m = soa.Decode<mirror::String*>(s);
+ ObjPtr<mirror::String> s_m = soa.Decode<mirror::String>(s);
ASSERT_TRUE(s != nullptr);
jchar expected[] = { 'h', 'e', 'l', 'l', 'o' };
@@ -2236,7 +2241,7 @@
static bool IsLocked(JNIEnv* env, jobject jobj) {
ScopedObjectAccess soa(env);
- LockWord lock_word = soa.Decode<mirror::Object*>(jobj)->GetLockWord(true);
+ LockWord lock_word = soa.Decode<mirror::Object>(jobj)->GetLockWord(true);
switch (lock_word.GetState()) {
case LockWord::kHashCode:
case LockWord::kUnlocked:
diff --git a/runtime/jobject_comparator.cc b/runtime/jobject_comparator.cc
index 1f424b3..443f095 100644
--- a/runtime/jobject_comparator.cc
+++ b/runtime/jobject_comparator.cc
@@ -19,7 +19,7 @@
#include "mirror/array-inl.h"
#include "mirror/class-inl.h"
#include "mirror/object-inl.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
namespace art {
@@ -32,8 +32,8 @@
}
ScopedObjectAccess soa(Thread::Current());
StackHandleScope<2> hs(soa.Self());
- Handle<mirror::Object> obj1(hs.NewHandle(soa.Decode<mirror::Object*>(jobj1)));
- Handle<mirror::Object> obj2(hs.NewHandle(soa.Decode<mirror::Object*>(jobj2)));
+ Handle<mirror::Object> obj1(hs.NewHandle(soa.Decode<mirror::Object>(jobj1)));
+ Handle<mirror::Object> obj2(hs.NewHandle(soa.Decode<mirror::Object>(jobj2)));
if (obj1.Get() == nullptr) {
return true;
} else if (obj2.Get() == nullptr) {
diff --git a/runtime/mirror/class.h b/runtime/mirror/class.h
index 548087e..6c1259b 100644
--- a/runtime/mirror/class.h
+++ b/runtime/mirror/class.h
@@ -54,9 +54,10 @@
class DexCache;
class IfTable;
class Method;
-struct StringDexCachePair;
+template <typename T> struct PACKED(8) DexCachePair;
-using StringDexCacheType = std::atomic<mirror::StringDexCachePair>;
+using StringDexCachePair = DexCachePair<mirror::String>;
+using StringDexCacheType = std::atomic<StringDexCachePair>;
// C++ mirror of java.lang.Class
class MANAGED Class FINAL : public Object {
diff --git a/runtime/mirror/dex_cache-inl.h b/runtime/mirror/dex_cache-inl.h
index 220979a..359462d 100644
--- a/runtime/mirror/dex_cache-inl.h
+++ b/runtime/mirror/dex_cache-inl.h
@@ -39,7 +39,7 @@
inline mirror::String* DexCache::GetResolvedString(uint32_t string_idx) {
DCHECK_LT(string_idx, GetDexFile()->NumStringIds());
- return StringDexCachePair::LookupString(GetStrings(), string_idx, NumStrings()).Read();
+ return StringDexCachePair::Lookup(GetStrings(), string_idx, NumStrings()).Read();
}
inline void DexCache::SetResolvedString(uint32_t string_idx, mirror::String* resolved) {
@@ -61,10 +61,10 @@
DCHECK(Runtime::Current()->IsAotCompiler());
StringDexCacheType* slot = &GetStrings()[slot_idx];
// This is racy but should only be called from the transactional interpreter.
- if (slot->load(std::memory_order_relaxed).string_index == string_idx) {
+ if (slot->load(std::memory_order_relaxed).index == string_idx) {
StringDexCachePair cleared(
nullptr,
- StringDexCachePair::InvalidStringIndexForSlot(slot_idx));
+ StringDexCachePair::InvalidIndexForSlot(slot_idx));
slot->store(cleared, std::memory_order_relaxed);
}
}
@@ -155,11 +155,11 @@
mirror::StringDexCacheType* strings = GetStrings();
for (size_t i = 0, num_strings = NumStrings(); i != num_strings; ++i) {
StringDexCachePair source = strings[i].load(std::memory_order_relaxed);
- mirror::String* before = source.string_pointer.Read<kReadBarrierOption>();
+ mirror::String* before = source.object.Read<kReadBarrierOption>();
GcRoot<mirror::String> root(before);
visitor.VisitRootIfNonNull(root.AddressWithoutBarrier());
if (root.Read() != before) {
- source.string_pointer = GcRoot<String>(root.Read());
+ source.object = GcRoot<String>(root.Read());
strings[i].store(source, std::memory_order_relaxed);
}
}
@@ -175,9 +175,9 @@
mirror::StringDexCacheType* src = GetStrings();
for (size_t i = 0, count = NumStrings(); i < count; ++i) {
StringDexCachePair source = src[i].load(std::memory_order_relaxed);
- mirror::String* ptr = source.string_pointer.Read<kReadBarrierOption>();
+ mirror::String* ptr = source.object.Read<kReadBarrierOption>();
mirror::String* new_source = visitor(ptr);
- source.string_pointer = GcRoot<String>(new_source);
+ source.object = GcRoot<String>(new_source);
dest[i].store(source, std::memory_order_relaxed);
}
}
diff --git a/runtime/mirror/dex_cache.h b/runtime/mirror/dex_cache.h
index 7d4021f..d81dedc 100644
--- a/runtime/mirror/dex_cache.h
+++ b/runtime/mirror/dex_cache.h
@@ -35,9 +35,9 @@
class String;
-struct PACKED(8) StringDexCachePair {
- GcRoot<String> string_pointer;
- uint32_t string_index;
+template <typename T> struct PACKED(8) DexCachePair {
+ GcRoot<T> object;
+ uint32_t index;
// The array is initially [ {0,0}, {0,0}, {0,0} ... ]
// We maintain the invariant that once a dex cache entry is populated,
// the pointer is always non-0
@@ -45,47 +45,51 @@
// {non-0, non-0} OR {0,0}
//
// It's generally sufficiently enough then to check if the
- // lookup string index matches the stored string index (for a >0 string index)
+ // lookup index matches the stored index (for a >0 lookup index)
// because if it's true the pointer is also non-null.
//
// For the 0th entry which is a special case, the value is either
// {0,0} (initial state) or {non-0, 0} which indicates
- // that a valid string is stored at that index for a dex string id of 0.
+ // that a valid object is stored at that index for a dex section id of 0.
//
- // As an optimization, we want to avoid branching on the string pointer since
- // it's always non-null if the string id branch succeeds (except for the 0th string id).
+ // As an optimization, we want to avoid branching on the object pointer since
+ // it's always non-null if the id branch succeeds (except for the 0th id).
// Set the initial state for the 0th entry to be {0,1} which is guaranteed to fail
- // the lookup string id == stored id branch.
- StringDexCachePair(String* string, uint32_t string_idx)
- : string_pointer(string),
- string_index(string_idx) {}
- StringDexCachePair() = default;
- StringDexCachePair(const StringDexCachePair&) = default;
- StringDexCachePair& operator=(const StringDexCachePair&) = default;
+ // the lookup id == stored id branch.
+ DexCachePair(T* object, uint32_t index)
+ : object(object),
+ index(index) {}
+ DexCachePair() = default;
+ DexCachePair(const DexCachePair<T>&) = default;
+ DexCachePair& operator=(const DexCachePair<T>&) = default;
- static void Initialize(StringDexCacheType* strings) {
- mirror::StringDexCachePair first_elem;
- first_elem.string_pointer = GcRoot<String>(nullptr);
- first_elem.string_index = InvalidStringIndexForSlot(0);
- strings[0].store(first_elem, std::memory_order_relaxed);
+ static void Initialize(std::atomic<DexCachePair<T>>* dex_cache) {
+ DexCachePair<T> first_elem;
+ first_elem.object = GcRoot<T>(nullptr);
+ first_elem.index = InvalidIndexForSlot(0);
+ dex_cache[0].store(first_elem, std::memory_order_relaxed);
}
- static GcRoot<String> LookupString(StringDexCacheType* dex_cache,
- uint32_t string_idx,
- uint32_t cache_size) {
- StringDexCachePair index_string = dex_cache[string_idx % cache_size]
- .load(std::memory_order_relaxed);
- if (string_idx != index_string.string_index) return GcRoot<String>(nullptr);
- DCHECK(!index_string.string_pointer.IsNull());
- return index_string.string_pointer;
+ static GcRoot<T> Lookup(std::atomic<DexCachePair<T>>* dex_cache,
+ uint32_t idx,
+ uint32_t cache_size) {
+ DexCachePair<T> element = dex_cache[idx % cache_size].load(std::memory_order_relaxed);
+ if (idx != element.index) {
+ return GcRoot<T>(nullptr);
+ }
+
+ DCHECK(!element.object.IsNull());
+ return element.object;
}
- static uint32_t InvalidStringIndexForSlot(uint32_t slot) {
+ static uint32_t InvalidIndexForSlot(uint32_t slot) {
// Since the cache size is a power of two, 0 will always map to slot 0.
// Use 1 for slot 0 and 0 for all other slots.
return (slot == 0) ? 1u : 0u;
}
};
+
+using StringDexCachePair = DexCachePair<mirror::String>;
using StringDexCacheType = std::atomic<StringDexCachePair>;
// C++ mirror of java.lang.DexCache.
diff --git a/runtime/mirror/dex_cache_test.cc b/runtime/mirror/dex_cache_test.cc
index 43ba362..ac04200 100644
--- a/runtime/mirror/dex_cache_test.cc
+++ b/runtime/mirror/dex_cache_test.cc
@@ -24,7 +24,7 @@
#include "mirror/class_loader-inl.h"
#include "mirror/dex_cache-inl.h"
#include "handle_scope-inl.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
namespace art {
namespace mirror {
@@ -56,7 +56,7 @@
ClassLinker* const class_linker = runtime->GetClassLinker();
StackHandleScope<1> hs(soa.Self());
Handle<mirror::ClassLoader> class_loader(hs.NewHandle(
- soa.Decode<mirror::ClassLoader*>(jclass_loader)));
+ soa.Decode<mirror::ClassLoader>(jclass_loader)));
mirror::Class* klass = class_linker->FindClass(soa.Self(), "LMain;", class_loader);
ASSERT_TRUE(klass != nullptr);
LinearAlloc* const linear_alloc = klass->GetClassLoader()->GetAllocator();
@@ -72,7 +72,7 @@
ClassLinker* const class_linker = runtime->GetClassLinker();
StackHandleScope<3> hs(soa.Self());
Handle<mirror::ClassLoader> class_loader(hs.NewHandle(
- soa.Decode<mirror::ClassLoader*>(jclass_loader)));
+ soa.Decode<mirror::ClassLoader>(jclass_loader)));
Handle<mirror::Class> klass1 =
hs.NewHandle(class_linker->FindClass(soa.Self(), "Lpackage1/Package1;", class_loader));
ASSERT_TRUE(klass1.Get() != nullptr);
diff --git a/runtime/mirror/method_handle_impl.cc b/runtime/mirror/method_handle_impl.cc
new file mode 100644
index 0000000..fdfaaa8
--- /dev/null
+++ b/runtime/mirror/method_handle_impl.cc
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "method_handle_impl.h"
+
+#include "class-inl.h"
+#include "gc_root-inl.h"
+
+namespace art {
+namespace mirror {
+
+GcRoot<mirror::Class> MethodHandleImpl::static_class_;
+
+void MethodHandleImpl::SetClass(Class* klass) {
+ CHECK(static_class_.IsNull()) << static_class_.Read() << " " << klass;
+ CHECK(klass != nullptr);
+ static_class_ = GcRoot<Class>(klass);
+}
+
+void MethodHandleImpl::ResetClass() {
+ CHECK(!static_class_.IsNull());
+ static_class_ = GcRoot<Class>(nullptr);
+}
+
+void MethodHandleImpl::VisitRoots(RootVisitor* visitor) {
+ static_class_.VisitRootIfNonNull(visitor, RootInfo(kRootStickyClass));
+}
+
+} // namespace mirror
+} // namespace art
diff --git a/runtime/mirror/method_handle_impl.h b/runtime/mirror/method_handle_impl.h
new file mode 100644
index 0000000..a0aae3c
--- /dev/null
+++ b/runtime/mirror/method_handle_impl.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_RUNTIME_MIRROR_METHOD_HANDLE_IMPL_H_
+#define ART_RUNTIME_MIRROR_METHOD_HANDLE_IMPL_H_
+
+#include "class.h"
+#include "gc_root.h"
+#include "object.h"
+#include "method_type.h"
+
+namespace art {
+
+struct MethodHandleImplOffsets;
+
+namespace mirror {
+
+// C++ mirror of java.lang.invoke.MethodHandle
+class MANAGED MethodHandle : public Object {
+ public:
+ mirror::MethodType* GetMethodType() REQUIRES_SHARED(Locks::mutator_lock_) {
+ return GetFieldObject<mirror::MethodType>(OFFSET_OF_OBJECT_MEMBER(MethodHandle, method_type_));
+ }
+
+ ArtMethod* GetTargetMethod() REQUIRES_SHARED(Locks::mutator_lock_) {
+ return reinterpret_cast<ArtMethod*>(
+ GetField64(OFFSET_OF_OBJECT_MEMBER(MethodHandle, art_field_or_method_)));
+ }
+
+ private:
+ HeapReference<mirror::Object> as_type_cache_;
+ HeapReference<mirror::MethodType> method_type_;
+ uint64_t art_field_or_method_;
+ uint32_t handle_kind_;
+
+ private:
+ static MemberOffset AsTypeCacheOffset() {
+ return MemberOffset(OFFSETOF_MEMBER(MethodHandle, as_type_cache_));
+ }
+ static MemberOffset MethodTypeOffset() {
+ return MemberOffset(OFFSETOF_MEMBER(MethodHandle, method_type_));
+ }
+ static MemberOffset ArtFieldOrMethodOffset() {
+ return MemberOffset(OFFSETOF_MEMBER(MethodHandle, art_field_or_method_));
+ }
+ static MemberOffset HandleKindOffset() {
+ return MemberOffset(OFFSETOF_MEMBER(MethodHandle, handle_kind_));
+ }
+
+ friend struct art::MethodHandleImplOffsets; // for verifying offset information
+ DISALLOW_IMPLICIT_CONSTRUCTORS(MethodHandle);
+};
+
+// C++ mirror of java.lang.invoke.MethodHandleImpl
+class MANAGED MethodHandleImpl : public MethodHandle {
+ public:
+ static mirror::Class* StaticClass() REQUIRES_SHARED(Locks::mutator_lock_) {
+ return static_class_.Read();
+ }
+
+ static void SetClass(Class* klass) REQUIRES_SHARED(Locks::mutator_lock_);
+ static void ResetClass() REQUIRES_SHARED(Locks::mutator_lock_);
+ static void VisitRoots(RootVisitor* visitor) REQUIRES_SHARED(Locks::mutator_lock_);
+
+ private:
+ static GcRoot<mirror::Class> static_class_; // java.lang.invoke.MethodHandleImpl.class
+
+ friend struct art::MethodHandleImplOffsets; // for verifying offset information
+ DISALLOW_IMPLICIT_CONSTRUCTORS(MethodHandleImpl);
+};
+
+} // namespace mirror
+} // namespace art
+
+#endif // ART_RUNTIME_MIRROR_METHOD_HANDLE_IMPL_H_
diff --git a/runtime/mirror/method_type.cc b/runtime/mirror/method_type.cc
new file mode 100644
index 0000000..ba6ea5e
--- /dev/null
+++ b/runtime/mirror/method_type.cc
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "method_type.h"
+
+#include "class-inl.h"
+#include "gc_root-inl.h"
+
+namespace art {
+namespace mirror {
+
+GcRoot<mirror::Class> MethodType::static_class_;
+
+mirror::MethodType* MethodType::Create(Thread* const self,
+ Handle<Class> return_type,
+ Handle<ObjectArray<Class>> param_types) {
+ StackHandleScope<1> hs(self);
+ Handle<mirror::MethodType> mt(
+ hs.NewHandle(static_cast<MethodType*>(StaticClass()->AllocObject(self))));
+
+ // TODO: Do we ever create a MethodType during a transaction ? There doesn't
+ // seem like a good reason to do a polymorphic invoke that results in the
+ // resolution of a method type in an unstarted runtime.
+ mt->SetFieldObject<false>(FormOffset(), nullptr);
+ mt->SetFieldObject<false>(MethodDescriptorOffset(), nullptr);
+ mt->SetFieldObject<false>(RTypeOffset(), return_type.Get());
+ mt->SetFieldObject<false>(PTypesOffset(), param_types.Get());
+ mt->SetFieldObject<false>(WrapAltOffset(), nullptr);
+
+ return mt.Get();
+}
+
+bool MethodType::IsExactMatch(mirror::MethodType* other) REQUIRES_SHARED(Locks::mutator_lock_) {
+ if (GetRType() != other->GetRType()) {
+ return false;
+ }
+
+ mirror::ObjectArray<Class>* const p_types = GetPTypes();
+ const int32_t params_length = p_types->GetLength();
+
+ mirror::ObjectArray<Class>* const other_p_types = other->GetPTypes();
+ if (params_length != other_p_types->GetLength()) {
+ return false;
+ }
+
+ for (int32_t i = 0; i < params_length; ++i) {
+ if (p_types->GetWithoutChecks(i) != other_p_types->GetWithoutChecks(i)) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+void MethodType::SetClass(Class* klass) {
+ CHECK(static_class_.IsNull()) << static_class_.Read() << " " << klass;
+ CHECK(klass != nullptr);
+ static_class_ = GcRoot<Class>(klass);
+}
+
+void MethodType::ResetClass() {
+ CHECK(!static_class_.IsNull());
+ static_class_ = GcRoot<Class>(nullptr);
+}
+
+void MethodType::VisitRoots(RootVisitor* visitor) {
+ static_class_.VisitRootIfNonNull(visitor, RootInfo(kRootStickyClass));
+}
+
+} // namespace mirror
+} // namespace art
diff --git a/runtime/mirror/method_type.h b/runtime/mirror/method_type.h
new file mode 100644
index 0000000..5b50409
--- /dev/null
+++ b/runtime/mirror/method_type.h
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_RUNTIME_MIRROR_METHOD_TYPE_H_
+#define ART_RUNTIME_MIRROR_METHOD_TYPE_H_
+
+#include "object.h"
+#include "string.h"
+#include "mirror/object_array.h"
+#include "utils.h"
+
+namespace art {
+
+struct MethodTypeOffsets;
+
+namespace mirror {
+
+// C++ mirror of java.lang.invoke.MethodType
+class MANAGED MethodType : public Object {
+ public:
+ static mirror::MethodType* Create(Thread* const self,
+ Handle<Class> return_type,
+ Handle<ObjectArray<Class>> param_types)
+ REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_);
+
+ static mirror::Class* StaticClass() REQUIRES_SHARED(Locks::mutator_lock_) {
+ return static_class_.Read();
+ }
+
+ ObjectArray<Class>* GetPTypes() REQUIRES_SHARED(Locks::mutator_lock_) {
+ return GetFieldObject<ObjectArray<Class>>(OFFSET_OF_OBJECT_MEMBER(MethodType, p_types_));
+ }
+
+ Class* GetRType() REQUIRES_SHARED(Locks::mutator_lock_) {
+ return GetFieldObject<Class>(OFFSET_OF_OBJECT_MEMBER(MethodType, r_type_));
+ }
+
+ static void SetClass(Class* klass) REQUIRES_SHARED(Locks::mutator_lock_);
+ static void ResetClass() REQUIRES_SHARED(Locks::mutator_lock_);
+ static void VisitRoots(RootVisitor* visitor) REQUIRES_SHARED(Locks::mutator_lock_);
+
+ // Returns true iff. |other| is an exact match for this method type, i.e
+ // iff. they have the same return types and parameter types.
+ bool IsExactMatch(mirror::MethodType* other) REQUIRES_SHARED(Locks::mutator_lock_);
+
+ private:
+ static MemberOffset FormOffset() {
+ return MemberOffset(OFFSETOF_MEMBER(MethodType, form_));
+ }
+
+ static MemberOffset MethodDescriptorOffset() {
+ return MemberOffset(OFFSETOF_MEMBER(MethodType, method_descriptor_));
+ }
+
+ static MemberOffset PTypesOffset() {
+ return MemberOffset(OFFSETOF_MEMBER(MethodType, p_types_));
+ }
+
+ static MemberOffset RTypeOffset() {
+ return MemberOffset(OFFSETOF_MEMBER(MethodType, r_type_));
+ }
+
+ static MemberOffset WrapAltOffset() {
+ return MemberOffset(OFFSETOF_MEMBER(MethodType, wrap_alt_));
+ }
+
+ HeapReference<mirror::Object> form_; // Unused in the runtime
+ HeapReference<mirror::String> method_descriptor_; // Unused in the runtime
+ HeapReference<ObjectArray<mirror::Class>> p_types_;
+ HeapReference<mirror::Class> r_type_;
+ HeapReference<mirror::Object> wrap_alt_; // Unused in the runtime
+
+ static GcRoot<mirror::Class> static_class_; // java.lang.invoke.MethodType.class
+
+ friend struct art::MethodTypeOffsets; // for verifying offset information
+ DISALLOW_IMPLICIT_CONSTRUCTORS(MethodType);
+};
+
+} // namespace mirror
+} // namespace art
+
+#endif // ART_RUNTIME_MIRROR_METHOD_TYPE_H_
diff --git a/runtime/mirror/method_type_test.cc b/runtime/mirror/method_type_test.cc
new file mode 100644
index 0000000..a968bff
--- /dev/null
+++ b/runtime/mirror/method_type_test.cc
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "method_type.h"
+
+#include <string>
+#include <vector>
+
+#include "class_linker.h"
+#include "common_runtime_test.h"
+#include "handle_scope-inl.h"
+#include "runtime/mirror/class.h"
+#include "runtime/mirror/class_loader.h"
+#include "scoped_thread_state_change.h"
+
+namespace art {
+namespace mirror {
+
+class MethodTypeTest : public CommonRuntimeTest {};
+
+static std::string FullyQualifiedType(const std::string& shorthand) {
+ return "Ljava/lang/" + shorthand + ";";
+}
+
+static mirror::MethodType* CreateMethodType(const std::string& return_type,
+ const std::vector<std::string>& param_types) {
+ CHECK_LT(param_types.size(), 3u);
+
+ Runtime* const runtime = Runtime::Current();
+ ClassLinker* const class_linker = runtime->GetClassLinker();
+ Thread* const self = Thread::Current();
+
+ ScopedObjectAccess soa(self);
+ StackHandleScope<5> hs(soa.Self());
+
+ Handle<mirror::ClassLoader> boot_class_loader = hs.NewHandle<mirror::ClassLoader>(nullptr);
+
+ Handle<mirror::Class> return_clazz = hs.NewHandle(class_linker->FindClass(
+ soa.Self(), FullyQualifiedType(return_type).c_str(), boot_class_loader));
+ CHECK(return_clazz.Get() != nullptr);
+
+ mirror::Class* class_type = mirror::Class::GetJavaLangClass();
+ mirror::Class* class_array_type = class_linker->FindArrayClass(self, &class_type);
+ Handle<mirror::ObjectArray<mirror::Class>> param_classes = hs.NewHandle(
+ mirror::ObjectArray<mirror::Class>::Alloc(self, class_array_type, param_types.size()));
+
+ for (uint32_t i = 0; i < param_types.size(); ++i) {
+ Handle<mirror::Class> param = hs.NewHandle(class_linker->FindClass(
+ soa.Self(), FullyQualifiedType(param_types[i]).c_str(), boot_class_loader));
+ param_classes->Set(i, param.Get());
+ }
+
+ return mirror::MethodType::Create(self, return_clazz, param_classes);
+}
+
+
+TEST_F(MethodTypeTest, IsExactMatch) {
+ ScopedObjectAccess soa(Thread::Current());
+ {
+ StackHandleScope<2> hs(soa.Self());
+ Handle<mirror::MethodType> mt1 = hs.NewHandle(CreateMethodType("String", { "Integer" }));
+ Handle<mirror::MethodType> mt2 = hs.NewHandle(CreateMethodType("String", { "Integer" }));
+ ASSERT_TRUE(mt1->IsExactMatch(mt2.Get()));
+ }
+
+ // Mismatched return type.
+ {
+ StackHandleScope<2> hs(soa.Self());
+ Handle<mirror::MethodType> mt1 = hs.NewHandle(CreateMethodType("String", { "Integer" }));
+ Handle<mirror::MethodType> mt2 = hs.NewHandle(CreateMethodType("Integer", { "Integer" }));
+ ASSERT_FALSE(mt1->IsExactMatch(mt2.Get()));
+ }
+
+ // Mismatched param types.
+ {
+ StackHandleScope<2> hs(soa.Self());
+ Handle<mirror::MethodType> mt1 = hs.NewHandle(CreateMethodType("String", { "Integer" }));
+ Handle<mirror::MethodType> mt2 = hs.NewHandle(CreateMethodType("String", { "String" }));
+ ASSERT_FALSE(mt1->IsExactMatch(mt2.Get()));
+ }
+
+ // Wrong number of param types.
+ {
+ StackHandleScope<2> hs(soa.Self());
+ Handle<mirror::MethodType> mt1 = hs.NewHandle(
+ CreateMethodType("String", { "String", "String" }));
+ Handle<mirror::MethodType> mt2 = hs.NewHandle(CreateMethodType("String", { "String" }));
+ ASSERT_FALSE(mt1->IsExactMatch(mt2.Get()));
+ }
+}
+
+} // namespace mirror
+} // namespace art
diff --git a/runtime/mirror/object-inl.h b/runtime/mirror/object-inl.h
index 0f5cbb2..ad7558c 100644
--- a/runtime/mirror/object-inl.h
+++ b/runtime/mirror/object-inl.h
@@ -31,6 +31,7 @@
#include "lock_word-inl.h"
#include "monitor.h"
#include "object_array-inl.h"
+#include "obj_ptr-inl.h"
#include "read_barrier-inl.h"
#include "reference.h"
#include "runtime.h"
@@ -281,7 +282,7 @@
}
template<VerifyObjectFlags kVerifyFlags>
-inline bool Object::InstanceOf(Class* klass) {
+inline bool Object::InstanceOf(ObjPtr<Class> klass) {
DCHECK(klass != nullptr);
DCHECK(GetClass<kVerifyNone>() != nullptr);
return klass->IsAssignableFrom(GetClass<kVerifyFlags>());
@@ -509,7 +510,7 @@
template GetObjectSize<kNewFlags, kReadBarrierOption>();
}
DCHECK_GE(result, sizeof(Object))
- << " class=" << PrettyTypeOf(GetClass<kNewFlags, kReadBarrierOption>());
+ << " class=" << PrettyClass(GetClass<kNewFlags, kReadBarrierOption>());
return result;
}
diff --git a/runtime/mirror/object.h b/runtime/mirror/object.h
index 262cb57..10faf60 100644
--- a/runtime/mirror/object.h
+++ b/runtime/mirror/object.h
@@ -20,6 +20,7 @@
#include "base/casts.h"
#include "base/enums.h"
#include "globals.h"
+#include "obj_ptr.h"
#include "object_reference.h"
#include "offsets.h"
#include "verify_object.h"
@@ -120,7 +121,7 @@
template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
bool VerifierInstanceOf(Class* klass) REQUIRES_SHARED(Locks::mutator_lock_);
template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
- ALWAYS_INLINE bool InstanceOf(Class* klass) REQUIRES_SHARED(Locks::mutator_lock_);
+ ALWAYS_INLINE bool InstanceOf(ObjPtr<Class> klass) REQUIRES_SHARED(Locks::mutator_lock_);
template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags,
ReadBarrierOption kReadBarrierOption = kWithReadBarrier>
diff --git a/runtime/mirror/object_test.cc b/runtime/mirror/object_test.cc
index f4ecfb5..40ee3a2 100644
--- a/runtime/mirror/object_test.cc
+++ b/runtime/mirror/object_test.cc
@@ -38,7 +38,7 @@
#include "obj_ptr.h"
#include "object-inl.h"
#include "object_array-inl.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
#include "string-inl.h"
namespace art {
@@ -365,7 +365,7 @@
const DexFile* dex_file = GetFirstDexFile(class_loader);
StackHandleScope<2> hs(soa.Self());
- Handle<mirror::ClassLoader> loader(hs.NewHandle(soa.Decode<ClassLoader*>(class_loader)));
+ Handle<mirror::ClassLoader> loader(hs.NewHandle(soa.Decode<ClassLoader>(class_loader)));
Class* klass = class_linker_->FindClass(soa.Self(), "LStaticsFromCode;", loader);
ArtMethod* clinit = klass->FindClassInitializer(kRuntimePointerSize);
const DexFile::TypeId* klass_type_id = dex_file->FindTypeId("LStaticsFromCode;");
@@ -495,8 +495,8 @@
jobject jclass_loader_1 = LoadDex("ProtoCompare");
jobject jclass_loader_2 = LoadDex("ProtoCompare2");
StackHandleScope<4> hs(soa.Self());
- Handle<ClassLoader> class_loader_1(hs.NewHandle(soa.Decode<ClassLoader*>(jclass_loader_1)));
- Handle<ClassLoader> class_loader_2(hs.NewHandle(soa.Decode<ClassLoader*>(jclass_loader_2)));
+ Handle<ClassLoader> class_loader_1(hs.NewHandle(soa.Decode<ClassLoader>(jclass_loader_1)));
+ Handle<ClassLoader> class_loader_2(hs.NewHandle(soa.Decode<ClassLoader>(jclass_loader_2)));
Class* klass1 = linker->FindClass(soa.Self(), "LProtoCompare;", class_loader_1);
ASSERT_TRUE(klass1 != nullptr);
@@ -538,7 +538,7 @@
ScopedObjectAccess soa(Thread::Current());
jobject jclass_loader = LoadDex("XandY");
StackHandleScope<3> hs(soa.Self());
- Handle<ClassLoader> class_loader(hs.NewHandle(soa.Decode<ClassLoader*>(jclass_loader)));
+ Handle<ClassLoader> class_loader(hs.NewHandle(soa.Decode<ClassLoader>(jclass_loader)));
Class* X = class_linker_->FindClass(soa.Self(), "LX;", class_loader);
Class* Y = class_linker_->FindClass(soa.Self(), "LY;", class_loader);
@@ -575,7 +575,7 @@
ScopedObjectAccess soa(Thread::Current());
jobject jclass_loader = LoadDex("XandY");
StackHandleScope<1> hs(soa.Self());
- Handle<ClassLoader> class_loader(hs.NewHandle(soa.Decode<ClassLoader*>(jclass_loader)));
+ Handle<ClassLoader> class_loader(hs.NewHandle(soa.Decode<ClassLoader>(jclass_loader)));
Class* X = class_linker_->FindClass(soa.Self(), "LX;", class_loader);
Class* Y = class_linker_->FindClass(soa.Self(), "LY;", class_loader);
@@ -613,7 +613,7 @@
ScopedObjectAccess soa(Thread::Current());
jobject jclass_loader = LoadDex("XandY");
StackHandleScope<1> hs(soa.Self());
- Handle<ClassLoader> class_loader(hs.NewHandle(soa.Decode<ClassLoader*>(jclass_loader)));
+ Handle<ClassLoader> class_loader(hs.NewHandle(soa.Decode<ClassLoader>(jclass_loader)));
Class* X = class_linker_->FindClass(soa.Self(), "LX;", class_loader);
Class* Y = class_linker_->FindClass(soa.Self(), "LY;", class_loader);
ASSERT_TRUE(X != nullptr);
@@ -746,25 +746,25 @@
ObjPtr<mirror::Object, /*kPoison*/ true> null_ptr;
EXPECT_TRUE(null_ptr.IsNull());
EXPECT_TRUE(null_ptr.IsValid());
- EXPECT_TRUE(null_ptr.Get() == nullptr);
+ EXPECT_TRUE(null_ptr.Decode() == nullptr);
EXPECT_TRUE(null_ptr == nullptr);
EXPECT_TRUE(null_ptr == null_ptr);
EXPECT_FALSE(null_ptr != null_ptr);
EXPECT_FALSE(null_ptr != nullptr);
null_ptr.AssertValid();
- Handle<ClassLoader> class_loader(hs.NewHandle(soa.Decode<ClassLoader*>(jclass_loader)));
+ Handle<ClassLoader> class_loader(hs.NewHandle(soa.Decode<ClassLoader>(jclass_loader)));
Handle<mirror::Class> h_X(
hs.NewHandle(class_linker_->FindClass(soa.Self(), "LX;", class_loader)));
ObjPtr<Class, /*kPoison*/ true> X(h_X.Get());
EXPECT_TRUE(!X.IsNull());
EXPECT_TRUE(X.IsValid());
- EXPECT_TRUE(X.Get() != nullptr);
- EXPECT_EQ(h_X.Get(), X.Get());
+ EXPECT_TRUE(X.Decode() != nullptr);
+ EXPECT_EQ(h_X.Get(), X.Decode());
// FindClass may cause thread suspension, it should invalidate X.
ObjPtr<Class, /*kPoison*/ true> Y(class_linker_->FindClass(soa.Self(), "LY;", class_loader));
EXPECT_TRUE(!Y.IsNull());
EXPECT_TRUE(Y.IsValid());
- EXPECT_TRUE(Y.Get() != nullptr);
+ EXPECT_TRUE(Y.Decode() != nullptr);
// Should IsNull be safe to call on null ObjPtr? I'll allow it for now.
EXPECT_TRUE(!X.IsNull());
@@ -773,7 +773,7 @@
X.Assign(h_X.Get());
EXPECT_TRUE(!X.IsNull());
EXPECT_TRUE(X.IsValid());
- EXPECT_EQ(h_X.Get(), X.Get());
+ EXPECT_EQ(h_X.Get(), X.Decode());
// Allow thread suspension to invalidate Y.
soa.Self()->AllowThreadSuspension();
@@ -784,7 +784,7 @@
ObjPtr<mirror::Object, /*kPoison*/ false> unpoisoned;
EXPECT_TRUE(unpoisoned.IsNull());
EXPECT_TRUE(unpoisoned.IsValid());
- EXPECT_TRUE(unpoisoned.Get() == nullptr);
+ EXPECT_TRUE(unpoisoned.Decode() == nullptr);
EXPECT_TRUE(unpoisoned == nullptr);
EXPECT_TRUE(unpoisoned == unpoisoned);
EXPECT_FALSE(unpoisoned != unpoisoned);
@@ -793,7 +793,7 @@
unpoisoned = h_X.Get();
EXPECT_FALSE(unpoisoned.IsNull());
EXPECT_TRUE(unpoisoned == h_X.Get());
- EXPECT_EQ(unpoisoned.Get(), h_X.Get());
+ EXPECT_EQ(unpoisoned.Decode(), h_X.Get());
}
} // namespace mirror
diff --git a/runtime/modifiers.h b/runtime/modifiers.h
index fd7a125..dd32df6 100644
--- a/runtime/modifiers.h
+++ b/runtime/modifiers.h
@@ -67,6 +67,7 @@
// Set by the verifier for a method that could not be verified to follow structured locking.
static constexpr uint32_t kAccMustCountLocks = 0x02000000; // method (runtime)
+static constexpr uint32_t kAccIntrinsic = 0x80000000; // method (runtime)
// Special runtime-only flags.
// Interface and all its super-interfaces with default methods have been recursively initialized.
@@ -76,6 +77,9 @@
// class/ancestor overrides finalize()
static constexpr uint32_t kAccClassIsFinalizable = 0x80000000;
+static constexpr uint32_t kAccFlagsNotUsedByIntrinsic = 0x007FFFFF;
+static constexpr uint32_t kAccMaxIntrinsic = 0xFF;
+
// Valid (meaningful) bits for a field.
static constexpr uint32_t kAccValidFieldFlags = kAccPublic | kAccPrivate | kAccProtected |
kAccStatic | kAccFinal | kAccVolatile | kAccTransient | kAccSynthetic | kAccEnum;
diff --git a/runtime/monitor.cc b/runtime/monitor.cc
index 49b83a7..3bc1b06 100644
--- a/runtime/monitor.cc
+++ b/runtime/monitor.cc
@@ -30,7 +30,7 @@
#include "mirror/class-inl.h"
#include "mirror/object-inl.h"
#include "mirror/object_array-inl.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
#include "thread.h"
#include "thread_list.h"
#include "verifier/method_verifier.h"
diff --git a/runtime/monitor_pool_test.cc b/runtime/monitor_pool_test.cc
index e1837f5..a111c6c 100644
--- a/runtime/monitor_pool_test.cc
+++ b/runtime/monitor_pool_test.cc
@@ -17,7 +17,7 @@
#include "monitor_pool.h"
#include "common_runtime_test.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
#include "thread-inl.h"
namespace art {
diff --git a/runtime/monitor_test.cc b/runtime/monitor_test.cc
index ac6a4f3..4ee46dc 100644
--- a/runtime/monitor_test.cc
+++ b/runtime/monitor_test.cc
@@ -27,7 +27,7 @@
#include "mirror/class-inl.h"
#include "mirror/string-inl.h" // Strings are easiest to allocate
#include "object_lock.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
#include "thread_pool.h"
namespace art {
diff --git a/runtime/native/dalvik_system_DexFile.cc b/runtime/native/dalvik_system_DexFile.cc
index 384de34..0677d5b 100644
--- a/runtime/native/dalvik_system_DexFile.cc
+++ b/runtime/native/dalvik_system_DexFile.cc
@@ -34,7 +34,7 @@
#include "oat_file_manager.h"
#include "os.h"
#include "runtime.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
#include "ScopedLocalRef.h"
#include "ScopedUtfChars.h"
#include "utils.h"
@@ -217,7 +217,7 @@
bool all_deleted = true;
{
ScopedObjectAccess soa(env);
- mirror::Object* dex_files_object = soa.Decode<mirror::Object*>(cookie);
+ ObjPtr<mirror::Object> dex_files_object = soa.Decode<mirror::Object>(cookie);
mirror::LongArray* long_dex_files = dex_files_object->AsLongArray();
// Delete dex files associated with this dalvik.system.DexFile since there should not be running
// code using it. dex_files is a vector due to multidex.
@@ -277,7 +277,7 @@
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
StackHandleScope<1> hs(soa.Self());
Handle<mirror::ClassLoader> class_loader(
- hs.NewHandle(soa.Decode<mirror::ClassLoader*>(javaLoader)));
+ hs.NewHandle(soa.Decode<mirror::ClassLoader>(javaLoader)));
class_linker->RegisterDexFile(*dex_file, class_loader.Get());
mirror::Class* result = class_linker->DefineClass(soa.Self(),
descriptor.c_str(),
@@ -287,7 +287,7 @@
*dex_class_def);
// Add the used dex file. This only required for the DexFile.loadClass API since normal
// class loaders already keep their dex files live.
- class_linker->InsertDexFileInToClassLoader(soa.Decode<mirror::Object*>(dexFile),
+ class_linker->InsertDexFileInToClassLoader(soa.Decode<mirror::Object>(dexFile).Decode(),
class_loader.Get());
if (result != nullptr) {
VLOG(class_linker) << "DexFile_defineClassNative returning " << result
diff --git a/runtime/native/dalvik_system_InMemoryDexClassLoader_DexData.cc b/runtime/native/dalvik_system_InMemoryDexClassLoader_DexData.cc
index 94933bc..fdced21 100644
--- a/runtime/native/dalvik_system_InMemoryDexClassLoader_DexData.cc
+++ b/runtime/native/dalvik_system_InMemoryDexClassLoader_DexData.cc
@@ -24,7 +24,7 @@
#include "mirror/class_loader.h"
#include "mirror/object-inl.h"
#include "oat_file.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
#include "ScopedUtfChars.h"
namespace art {
@@ -148,7 +148,7 @@
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
StackHandleScope<1> handle_scope(soa.Self());
Handle<mirror::ClassLoader> class_loader(
- handle_scope.NewHandle(soa.Decode<mirror::ClassLoader*>(loader)));
+ handle_scope.NewHandle(soa.Decode<mirror::ClassLoader>(loader)));
class_linker->RegisterDexFile(*dex_file, class_loader.Get());
mirror::Class* result = class_linker->DefineClass(
soa.Self(), class_descriptor, hash, class_loader, *dex_file, *dex_class_def);
@@ -157,7 +157,7 @@
// InMemoryClassLoader/DexData instance now that a class has
// been loaded.
class_linker->InsertDexFileInToClassLoader(
- soa.Decode<mirror::Object*>(dexData), class_loader.Get());
+ soa.Decode<mirror::Object>(dexData).Decode(), class_loader.Get());
return soa.AddLocalReference<jclass>(result);
}
}
diff --git a/runtime/native/dalvik_system_VMDebug.cc b/runtime/native/dalvik_system_VMDebug.cc
index f09c067..73c4664 100644
--- a/runtime/native/dalvik_system_VMDebug.cc
+++ b/runtime/native/dalvik_system_VMDebug.cc
@@ -36,7 +36,7 @@
#include "mirror/class.h"
#include "ScopedLocalRef.h"
#include "ScopedUtfChars.h"
-#include "scoped_fast_native_object_access.h"
+#include "scoped_fast_native_object_access-inl.h"
#include "trace.h"
#include "well_known_classes.h"
@@ -259,11 +259,11 @@
ScopedObjectAccess soa(env);
gc::Heap* const heap = Runtime::Current()->GetHeap();
// Caller's responsibility to do GC if desired.
- mirror::Class* c = soa.Decode<mirror::Class*>(javaClass);
+ ObjPtr<mirror::Class> c = soa.Decode<mirror::Class>(javaClass);
if (c == nullptr) {
return 0;
}
- std::vector<mirror::Class*> classes {c};
+ std::vector<mirror::Class*> classes {c.Decode()};
uint64_t count = 0;
heap->CountInstances(classes, countAssignable, &count);
return count;
@@ -274,7 +274,8 @@
ScopedObjectAccess soa(env);
gc::Heap* const heap = Runtime::Current()->GetHeap();
// Caller's responsibility to do GC if desired.
- auto* decoded_classes = soa.Decode<mirror::ObjectArray<mirror::Class>*>(javaClasses);
+ ObjPtr<mirror::ObjectArray<mirror::Class>> decoded_classes =
+ soa.Decode<mirror::ObjectArray<mirror::Class>>(javaClasses);
if (decoded_classes == nullptr) {
return nullptr;
}
diff --git a/runtime/native/dalvik_system_VMRuntime.cc b/runtime/native/dalvik_system_VMRuntime.cc
index d88c9d4..c7fb44ec 100644
--- a/runtime/native/dalvik_system_VMRuntime.cc
+++ b/runtime/native/dalvik_system_VMRuntime.cc
@@ -46,8 +46,8 @@
#include "mirror/dex_cache-inl.h"
#include "mirror/object-inl.h"
#include "runtime.h"
-#include "scoped_fast_native_object_access.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_fast_native_object_access-inl.h"
+#include "scoped_thread_state_change-inl.h"
#include "thread.h"
#include "thread_list.h"
@@ -74,7 +74,7 @@
ThrowNegativeArraySizeException(length);
return nullptr;
}
- mirror::Class* element_class = soa.Decode<mirror::Class*>(javaElementClass);
+ mirror::Class* element_class = soa.Decode<mirror::Class>(javaElementClass).Decode();
if (UNLIKELY(element_class == nullptr)) {
ThrowNullPointerException("element class == null");
return nullptr;
@@ -99,7 +99,7 @@
ThrowNegativeArraySizeException(length);
return nullptr;
}
- mirror::Class* element_class = soa.Decode<mirror::Class*>(javaElementClass);
+ mirror::Class* element_class = soa.Decode<mirror::Class>(javaElementClass).Decode();
if (UNLIKELY(element_class == nullptr)) {
ThrowNullPointerException("element class == null");
return nullptr;
@@ -122,12 +122,12 @@
return 0;
}
ScopedFastNativeObjectAccess soa(env);
- mirror::Array* array = soa.Decode<mirror::Array*>(javaArray);
+ ObjPtr<mirror::Array> array = soa.Decode<mirror::Array>(javaArray);
if (!array->IsArrayInstance()) {
ThrowIllegalArgumentException("not an array");
return 0;
}
- if (Runtime::Current()->GetHeap()->IsMovableObject(array)) {
+ if (Runtime::Current()->GetHeap()->IsMovableObject(array.Decode())) {
ThrowRuntimeException("Trying to get address of movable array object");
return 0;
}
diff --git a/runtime/native/dalvik_system_VMStack.cc b/runtime/native/dalvik_system_VMStack.cc
index 9da40b9..0dd8cdd 100644
--- a/runtime/native/dalvik_system_VMStack.cc
+++ b/runtime/native/dalvik_system_VMStack.cc
@@ -22,8 +22,8 @@
#include "mirror/class-inl.h"
#include "mirror/class_loader.h"
#include "mirror/object-inl.h"
-#include "scoped_fast_native_object_access.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_fast_native_object_access-inl.h"
+#include "scoped_thread_state_change-inl.h"
#include "thread_list.h"
namespace art {
@@ -31,7 +31,7 @@
static jobject GetThreadStack(const ScopedFastNativeObjectAccess& soa, jobject peer)
REQUIRES_SHARED(Locks::mutator_lock_) {
jobject trace = nullptr;
- if (soa.Decode<mirror::Object*>(peer) == soa.Self()->GetPeer()) {
+ if (soa.Decode<mirror::Object>(peer) == soa.Self()->GetPeer()) {
trace = soa.Self()->CreateInternalStackTrace<false>(soa);
} else {
// Suspend thread to build stack trace.
diff --git a/runtime/native/dalvik_system_ZygoteHooks.cc b/runtime/native/dalvik_system_ZygoteHooks.cc
index fe3cbe7..a78909b 100644
--- a/runtime/native/dalvik_system_ZygoteHooks.cc
+++ b/runtime/native/dalvik_system_ZygoteHooks.cc
@@ -24,7 +24,7 @@
#include "jit/jit.h"
#include "jni_internal.h"
#include "JNIHelp.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
#include "ScopedUtfChars.h"
#include "thread-inl.h"
#include "trace.h"
diff --git a/runtime/native/java_lang_Class.cc b/runtime/native/java_lang_Class.cc
index af9b68f..34bd57b 100644
--- a/runtime/native/java_lang_Class.cc
+++ b/runtime/native/java_lang_Class.cc
@@ -33,9 +33,10 @@
#include "mirror/object-inl.h"
#include "mirror/object_array-inl.h"
#include "mirror/string-inl.h"
+#include "obj_ptr-inl.h"
#include "reflection.h"
-#include "scoped_thread_state_change.h"
-#include "scoped_fast_native_object_access.h"
+#include "scoped_thread_state_change-inl.h"
+#include "scoped_fast_native_object_access-inl.h"
#include "ScopedLocalRef.h"
#include "ScopedUtfChars.h"
#include "utf.h"
@@ -43,10 +44,10 @@
namespace art {
-ALWAYS_INLINE static inline mirror::Class* DecodeClass(
+ALWAYS_INLINE static inline ObjPtr<mirror::Class> DecodeClass(
const ScopedFastNativeObjectAccess& soa, jobject java_class)
REQUIRES_SHARED(Locks::mutator_lock_) {
- mirror::Class* c = soa.Decode<mirror::Class*>(java_class);
+ ObjPtr<mirror::Class> c = soa.Decode<mirror::Class>(java_class);
DCHECK(c != nullptr);
DCHECK(c->IsClass());
// TODO: we could EnsureInitialized here, rather than on every reflective get/set or invoke .
@@ -75,16 +76,19 @@
std::string descriptor(DotToDescriptor(name.c_str()));
StackHandleScope<2> hs(soa.Self());
- Handle<mirror::ClassLoader> class_loader(hs.NewHandle(soa.Decode<mirror::ClassLoader*>(javaLoader)));
+ Handle<mirror::ClassLoader> class_loader(
+ hs.NewHandle(soa.Decode<mirror::ClassLoader>(javaLoader)));
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
Handle<mirror::Class> c(
hs.NewHandle(class_linker->FindClass(soa.Self(), descriptor.c_str(), class_loader)));
if (c.Get() == nullptr) {
ScopedLocalRef<jthrowable> cause(env, env->ExceptionOccurred());
env->ExceptionClear();
- jthrowable cnfe = reinterpret_cast<jthrowable>(env->NewObject(WellKnownClasses::java_lang_ClassNotFoundException,
- WellKnownClasses::java_lang_ClassNotFoundException_init,
- javaName, cause.get()));
+ jthrowable cnfe = reinterpret_cast<jthrowable>(
+ env->NewObject(WellKnownClasses::java_lang_ClassNotFoundException,
+ WellKnownClasses::java_lang_ClassNotFoundException_init,
+ javaName,
+ cause.get()));
if (cnfe != nullptr) {
// Make sure allocation didn't fail with an OOME.
env->Throw(cnfe);
@@ -100,18 +104,18 @@
static jstring Class_getNameNative(JNIEnv* env, jobject javaThis) {
ScopedFastNativeObjectAccess soa(env);
StackHandleScope<1> hs(soa.Self());
- mirror::Class* const c = DecodeClass(soa, javaThis);
+ ObjPtr<mirror::Class> c = DecodeClass(soa, javaThis);
return soa.AddLocalReference<jstring>(mirror::Class::ComputeName(hs.NewHandle(c)));
}
static jobjectArray Class_getProxyInterfaces(JNIEnv* env, jobject javaThis) {
ScopedFastNativeObjectAccess soa(env);
- mirror::Class* c = DecodeClass(soa, javaThis);
+ ObjPtr<mirror::Class> c = DecodeClass(soa, javaThis);
return soa.AddLocalReference<jobjectArray>(c->GetInterfaces()->Clone(soa.Self()));
}
static mirror::ObjectArray<mirror::Field>* GetDeclaredFields(
- Thread* self, mirror::Class* klass, bool public_only, bool force_resolve)
+ Thread* self, ObjPtr<mirror::Class> klass, bool public_only, bool force_resolve)
REQUIRES_SHARED(Locks::mutator_lock_) {
StackHandleScope<1> hs(self);
IterationRange<StrideIterator<ArtField>> ifields = klass->GetIFields();
@@ -191,8 +195,8 @@
// Performs a binary search through an array of fields, TODO: Is this fast enough if we don't use
// the dex cache for lookups? I think CompareModifiedUtf8ToUtf16AsCodePointValues should be fairly
// fast.
-ALWAYS_INLINE static inline ArtField* FindFieldByName(
- Thread* self ATTRIBUTE_UNUSED, mirror::String* name, LengthPrefixedArray<ArtField>* fields)
+ALWAYS_INLINE static inline ArtField* FindFieldByName(ObjPtr<mirror::String> name,
+ LengthPrefixedArray<ArtField>* fields)
REQUIRES_SHARED(Locks::mutator_lock_) {
if (fields == nullptr) {
return nullptr;
@@ -236,14 +240,15 @@
return nullptr;
}
-ALWAYS_INLINE static inline mirror::Field* GetDeclaredField(
- Thread* self, mirror::Class* c, mirror::String* name)
+ALWAYS_INLINE static inline mirror::Field* GetDeclaredField(Thread* self,
+ ObjPtr<mirror::Class> c,
+ ObjPtr<mirror::String> name)
REQUIRES_SHARED(Locks::mutator_lock_) {
- ArtField* art_field = FindFieldByName(self, name, c->GetIFieldsPtr());
+ ArtField* art_field = FindFieldByName(name, c->GetIFieldsPtr());
if (art_field != nullptr) {
return mirror::Field::CreateFromArtField<kRuntimePointerSize>(self, art_field, true);
}
- art_field = FindFieldByName(self, name, c->GetSFieldsPtr());
+ art_field = FindFieldByName(name, c->GetSFieldsPtr());
if (art_field != nullptr) {
return mirror::Field::CreateFromArtField<kRuntimePointerSize>(self, art_field, true);
}
@@ -251,7 +256,7 @@
}
static mirror::Field* GetPublicFieldRecursive(
- Thread* self, mirror::Class* clazz, mirror::String* name)
+ Thread* self, ObjPtr<mirror::Class> clazz, ObjPtr<mirror::String> name)
REQUIRES_SHARED(Locks::mutator_lock_) {
DCHECK(clazz != nullptr);
DCHECK(name != nullptr);
@@ -301,7 +306,7 @@
static jobject Class_getPublicFieldRecursive(JNIEnv* env, jobject javaThis, jstring name) {
ScopedFastNativeObjectAccess soa(env);
- auto* name_string = soa.Decode<mirror::String*>(name);
+ auto name_string = soa.Decode<mirror::String>(name);
if (UNLIKELY(name_string == nullptr)) {
ThrowNullPointerException("name == null");
return nullptr;
@@ -312,16 +317,18 @@
static jobject Class_getDeclaredField(JNIEnv* env, jobject javaThis, jstring name) {
ScopedFastNativeObjectAccess soa(env);
- auto* name_string = soa.Decode<mirror::String*>(name);
- if (name_string == nullptr) {
+ StackHandleScope<3> hs(soa.Self());
+ Handle<mirror::String> h_string = hs.NewHandle(soa.Decode<mirror::String>(name));
+ if (h_string.Get() == nullptr) {
ThrowNullPointerException("name == null");
return nullptr;
}
- auto* klass = DecodeClass(soa, javaThis);
- mirror::Field* result = GetDeclaredField(soa.Self(), klass, name_string);
- if (result == nullptr) {
- std::string name_str = name_string->ToModifiedUtf8();
- if (name_str == "value" && klass->IsStringClass()) {
+ Handle<mirror::Class> h_klass = hs.NewHandle(DecodeClass(soa, javaThis));
+ Handle<mirror::Field> result =
+ hs.NewHandle(GetDeclaredField(soa.Self(), h_klass.Get(), h_string.Get()));
+ if (result.Get() == nullptr) {
+ std::string name_str = h_string->ToModifiedUtf8();
+ if (name_str == "value" && h_klass->IsStringClass()) {
// We log the error for this specific case, as the user might just swallow the exception.
// This helps diagnose crashes when applications rely on the String#value field being
// there.
@@ -332,11 +339,11 @@
}
// We may have a pending exception if we failed to resolve.
if (!soa.Self()->IsExceptionPending()) {
- ThrowNoSuchFieldException(DecodeClass(soa, javaThis), name_str.c_str());
+ ThrowNoSuchFieldException(h_klass.Get(), name_str.c_str());
}
return nullptr;
}
- return soa.AddLocalReference<jobject>(result);
+ return soa.AddLocalReference<jobject>(result.Get());
}
static jobject Class_getDeclaredConstructorInternal(
@@ -344,11 +351,11 @@
ScopedFastNativeObjectAccess soa(env);
DCHECK_EQ(Runtime::Current()->GetClassLinker()->GetImagePointerSize(), kRuntimePointerSize);
DCHECK(!Runtime::Current()->IsActiveTransaction());
- mirror::Constructor* result = mirror::Class::GetDeclaredConstructorInternal<kRuntimePointerSize,
- false>(
+ ObjPtr<mirror::Constructor> result =
+ mirror::Class::GetDeclaredConstructorInternal<kRuntimePointerSize, false>(
soa.Self(),
- DecodeClass(soa, javaThis),
- soa.Decode<mirror::ObjectArray<mirror::Class>*>(args));
+ DecodeClass(soa, javaThis).Decode(),
+ soa.Decode<mirror::ObjectArray<mirror::Class>>(args).Decode());
return soa.AddLocalReference<jobject>(result);
}
@@ -398,9 +405,9 @@
DCHECK(!Runtime::Current()->IsActiveTransaction());
mirror::Method* result = mirror::Class::GetDeclaredMethodInternal<kRuntimePointerSize, false>(
soa.Self(),
- DecodeClass(soa, javaThis),
- soa.Decode<mirror::String*>(name),
- soa.Decode<mirror::ObjectArray<mirror::Class>*>(args));
+ DecodeClass(soa, javaThis).Decode(),
+ soa.Decode<mirror::String>(name).Decode(),
+ soa.Decode<mirror::ObjectArray<mirror::Class>>(args).Decode());
return soa.AddLocalReference<jobject>(result);
}
@@ -453,7 +460,7 @@
if (klass->IsProxyClass() || klass->GetDexCache() == nullptr) {
return nullptr;
}
- Handle<mirror::Class> annotation_class(hs.NewHandle(soa.Decode<mirror::Class*>(annotationClass)));
+ Handle<mirror::Class> annotation_class(hs.NewHandle(soa.Decode<mirror::Class>(annotationClass)));
return soa.AddLocalReference<jobject>(
annotations::GetAnnotationForClass(klass, annotation_class));
}
@@ -464,10 +471,12 @@
Handle<mirror::Class> klass(hs.NewHandle(DecodeClass(soa, javaThis)));
if (klass->IsProxyClass() || klass->GetDexCache() == nullptr) {
// Return an empty array instead of a null pointer.
- mirror::Class* annotation_array_class =
- soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_annotation_Annotation__array);
+ ObjPtr<mirror::Class> annotation_array_class =
+ soa.Decode<mirror::Class>(WellKnownClasses::java_lang_annotation_Annotation__array);
mirror::ObjectArray<mirror::Object>* empty_array =
- mirror::ObjectArray<mirror::Object>::Alloc(soa.Self(), annotation_array_class, 0);
+ mirror::ObjectArray<mirror::Object>::Alloc(soa.Self(),
+ annotation_array_class.Decode(),
+ 0);
return soa.AddLocalReference<jobjectArray>(empty_array);
}
return soa.AddLocalReference<jobjectArray>(annotations::GetAnnotationsForClass(klass));
@@ -519,8 +528,8 @@
}
mirror::Object* method = annotations::GetEnclosingMethod(klass);
if (method != nullptr) {
- if (method->GetClass() ==
- soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_reflect_Constructor)) {
+ if (soa.Decode<mirror::Class>(WellKnownClasses::java_lang_reflect_Constructor) ==
+ method->GetClass()) {
return soa.AddLocalReference<jobject>(method);
}
}
@@ -536,8 +545,8 @@
}
mirror::Object* method = annotations::GetEnclosingMethod(klass);
if (method != nullptr) {
- if (method->GetClass() ==
- soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_reflect_Method)) {
+ if (soa.Decode<mirror::Class>(WellKnownClasses::java_lang_reflect_Method) ==
+ method->GetClass()) {
return soa.AddLocalReference<jobject>(method);
}
}
@@ -598,7 +607,7 @@
if (klass->IsProxyClass() || klass->GetDexCache() == nullptr) {
return false;
}
- Handle<mirror::Class> annotation_class(hs.NewHandle(soa.Decode<mirror::Class*>(annotationType)));
+ Handle<mirror::Class> annotation_class(hs.NewHandle(soa.Decode<mirror::Class>(annotationType)));
return annotations::IsClassAnnotationPresent(klass, annotation_class);
}
@@ -669,7 +678,10 @@
caller.Assign(GetCallingClass(soa.Self(), 1));
}
if (UNLIKELY(caller.Get() != nullptr && !VerifyAccess(
- receiver.Get(), declaring_class, constructor->GetAccessFlags(), caller.Get()))) {
+ MakeObjPtr(receiver.Get()),
+ MakeObjPtr(declaring_class),
+ constructor->GetAccessFlags(),
+ MakeObjPtr(caller.Get())))) {
soa.Self()->ThrowNewExceptionF(
"Ljava/lang/IllegalAccessException;", "%s is not accessible from %s",
PrettyMethod(constructor).c_str(), PrettyClass(caller.Get()).c_str());
diff --git a/runtime/native/java_lang_DexCache.cc b/runtime/native/java_lang_DexCache.cc
index f0140a3..5efafe7 100644
--- a/runtime/native/java_lang_DexCache.cc
+++ b/runtime/native/java_lang_DexCache.cc
@@ -21,14 +21,14 @@
#include "mirror/class-inl.h"
#include "mirror/dex_cache-inl.h"
#include "mirror/object-inl.h"
-#include "scoped_fast_native_object_access.h"
+#include "scoped_fast_native_object_access-inl.h"
#include "well_known_classes.h"
namespace art {
static jobject DexCache_getDexNative(JNIEnv* env, jobject javaDexCache) {
ScopedFastNativeObjectAccess soa(env);
- mirror::DexCache* dex_cache = soa.Decode<mirror::DexCache*>(javaDexCache);
+ ObjPtr<mirror::DexCache> dex_cache = soa.Decode<mirror::DexCache>(javaDexCache);
// Should only be called while holding the lock on the dex cache.
DCHECK_EQ(dex_cache->GetLockOwnerThreadId(), soa.Self()->GetThreadId());
const DexFile* dex_file = dex_cache->GetDexFile();
@@ -51,14 +51,14 @@
static jobject DexCache_getResolvedType(JNIEnv* env, jobject javaDexCache, jint type_index) {
ScopedFastNativeObjectAccess soa(env);
- mirror::DexCache* dex_cache = soa.Decode<mirror::DexCache*>(javaDexCache);
+ ObjPtr<mirror::DexCache> dex_cache = soa.Decode<mirror::DexCache>(javaDexCache);
CHECK_LT(static_cast<size_t>(type_index), dex_cache->NumResolvedTypes());
return soa.AddLocalReference<jobject>(dex_cache->GetResolvedType(type_index));
}
static jobject DexCache_getResolvedString(JNIEnv* env, jobject javaDexCache, jint string_index) {
ScopedFastNativeObjectAccess soa(env);
- mirror::DexCache* dex_cache = soa.Decode<mirror::DexCache*>(javaDexCache);
+ ObjPtr<mirror::DexCache> dex_cache = soa.Decode<mirror::DexCache>(javaDexCache);
CHECK_LT(static_cast<size_t>(string_index), dex_cache->GetDexFile()->NumStringIds());
return soa.AddLocalReference<jobject>(dex_cache->GetResolvedString(string_index));
}
@@ -66,17 +66,17 @@
static void DexCache_setResolvedType(JNIEnv* env, jobject javaDexCache, jint type_index,
jobject type) {
ScopedFastNativeObjectAccess soa(env);
- mirror::DexCache* dex_cache = soa.Decode<mirror::DexCache*>(javaDexCache);
+ ObjPtr<mirror::DexCache> dex_cache = soa.Decode<mirror::DexCache>(javaDexCache);
CHECK_LT(static_cast<size_t>(type_index), dex_cache->NumResolvedTypes());
- dex_cache->SetResolvedType(type_index, soa.Decode<mirror::Class*>(type));
+ dex_cache->SetResolvedType(type_index, soa.Decode<mirror::Class>(type).Decode());
}
static void DexCache_setResolvedString(JNIEnv* env, jobject javaDexCache, jint string_index,
jobject string) {
ScopedFastNativeObjectAccess soa(env);
- mirror::DexCache* dex_cache = soa.Decode<mirror::DexCache*>(javaDexCache);
+ ObjPtr<mirror::DexCache> dex_cache = soa.Decode<mirror::DexCache>(javaDexCache);
CHECK_LT(static_cast<size_t>(string_index), dex_cache->GetDexFile()->NumStringIds());
- dex_cache->SetResolvedString(string_index, soa.Decode<mirror::String*>(string));
+ dex_cache->SetResolvedString(string_index, soa.Decode<mirror::String>(string).Decode());
}
static JNINativeMethod gMethods[] = {
diff --git a/runtime/native/java_lang_Object.cc b/runtime/native/java_lang_Object.cc
index 2a36059..6493865 100644
--- a/runtime/native/java_lang_Object.cc
+++ b/runtime/native/java_lang_Object.cc
@@ -18,39 +18,35 @@
#include "jni_internal.h"
#include "mirror/object-inl.h"
-#include "scoped_fast_native_object_access.h"
+#include "scoped_fast_native_object_access-inl.h"
namespace art {
static jobject Object_internalClone(JNIEnv* env, jobject java_this) {
ScopedFastNativeObjectAccess soa(env);
- mirror::Object* o = soa.Decode<mirror::Object*>(java_this);
+ ObjPtr<mirror::Object> o = soa.Decode<mirror::Object>(java_this);
return soa.AddLocalReference<jobject>(o->Clone(soa.Self()));
}
static void Object_notify(JNIEnv* env, jobject java_this) {
ScopedFastNativeObjectAccess soa(env);
- mirror::Object* o = soa.Decode<mirror::Object*>(java_this);
- o->Notify(soa.Self());
+ soa.Decode<mirror::Object>(java_this)->Notify(soa.Self());
}
static void Object_notifyAll(JNIEnv* env, jobject java_this) {
ScopedFastNativeObjectAccess soa(env);
- mirror::Object* o = soa.Decode<mirror::Object*>(java_this);
- o->NotifyAll(soa.Self());
+ soa.Decode<mirror::Object>(java_this)->NotifyAll(soa.Self());
}
static void Object_wait(JNIEnv* env, jobject java_this) {
ScopedFastNativeObjectAccess soa(env);
- mirror::Object* o = soa.Decode<mirror::Object*>(java_this);
- o->Wait(soa.Self());
+ soa.Decode<mirror::Object>(java_this)->Wait(soa.Self());
}
static void Object_waitJI(JNIEnv* env, jobject java_this, jlong ms, jint ns) {
ScopedFastNativeObjectAccess soa(env);
- mirror::Object* o = soa.Decode<mirror::Object*>(java_this);
- o->Wait(soa.Self(), ms, ns);
+ soa.Decode<mirror::Object>(java_this)->Wait(soa.Self(), ms, ns);
}
static JNINativeMethod gMethods[] = {
diff --git a/runtime/native/java_lang_String.cc b/runtime/native/java_lang_String.cc
index aa64b79..b3a967d 100644
--- a/runtime/native/java_lang_String.cc
+++ b/runtime/native/java_lang_String.cc
@@ -22,8 +22,8 @@
#include "mirror/object-inl.h"
#include "mirror/string.h"
#include "mirror/string-inl.h"
-#include "scoped_fast_native_object_access.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_fast_native_object_access-inl.h"
+#include "scoped_thread_state_change-inl.h"
#include "ScopedLocalRef.h"
#include "verify_object-inl.h"
@@ -31,7 +31,7 @@
static jchar String_charAt(JNIEnv* env, jobject java_this, jint index) {
ScopedFastNativeObjectAccess soa(env);
- return soa.Decode<mirror::String*>(java_this)->CharAt(index);
+ return soa.Decode<mirror::String>(java_this)->CharAt(index);
}
static jint String_compareTo(JNIEnv* env, jobject java_this, jobject java_rhs) {
@@ -40,7 +40,8 @@
ThrowNullPointerException("rhs == null");
return -1;
} else {
- return soa.Decode<mirror::String*>(java_this)->CompareTo(soa.Decode<mirror::String*>(java_rhs));
+ return soa.Decode<mirror::String>(java_this)->CompareTo(
+ soa.Decode<mirror::String>(java_rhs).Decode());
}
}
@@ -51,8 +52,8 @@
return nullptr;
}
StackHandleScope<2> hs(soa.Self());
- Handle<mirror::String> string_this(hs.NewHandle(soa.Decode<mirror::String*>(java_this)));
- Handle<mirror::String> string_arg(hs.NewHandle(soa.Decode<mirror::String*>(java_string_arg)));
+ Handle<mirror::String> string_this(hs.NewHandle(soa.Decode<mirror::String>(java_this)));
+ Handle<mirror::String> string_arg(hs.NewHandle(soa.Decode<mirror::String>(java_string_arg)));
int32_t length_this = string_this->GetLength();
int32_t length_arg = string_arg->GetLength();
if (length_arg > 0 && length_this > 0) {
@@ -67,13 +68,13 @@
ScopedFastNativeObjectAccess soa(env);
// This method does not handle supplementary characters. They're dealt with in managed code.
DCHECK_LE(ch, 0xffff);
- return soa.Decode<mirror::String*>(java_this)->FastIndexOf(ch, start);
+ return soa.Decode<mirror::String>(java_this)->FastIndexOf(ch, start);
}
static jstring String_fastSubstring(JNIEnv* env, jobject java_this, jint start, jint length) {
ScopedFastNativeObjectAccess soa(env);
StackHandleScope<1> hs(soa.Self());
- Handle<mirror::String> string_this(hs.NewHandle(soa.Decode<mirror::String*>(java_this)));
+ Handle<mirror::String> string_this(hs.NewHandle(soa.Decode<mirror::String>(java_this)));
gc::AllocatorType allocator_type = Runtime::Current()->GetHeap()->GetCurrentAllocator();
mirror::String* result = mirror::String::AllocFromString<true>(soa.Self(), length, string_this,
start, allocator_type);
@@ -84,25 +85,24 @@
jcharArray buffer, jint index) {
ScopedFastNativeObjectAccess soa(env);
StackHandleScope<1> hs(soa.Self());
- Handle<mirror::CharArray> char_array(hs.NewHandle(soa.Decode<mirror::CharArray*>(buffer)));
- soa.Decode<mirror::String*>(java_this)->GetChars(start, end, char_array, index);
+ Handle<mirror::CharArray> char_array(hs.NewHandle(soa.Decode<mirror::CharArray>(buffer)));
+ soa.Decode<mirror::String>(java_this)->GetChars(start, end, char_array, index);
}
static jstring String_intern(JNIEnv* env, jobject java_this) {
ScopedFastNativeObjectAccess soa(env);
- mirror::String* s = soa.Decode<mirror::String*>(java_this);
- mirror::String* result = s->Intern();
+ ObjPtr<mirror::String> result = soa.Decode<mirror::String>(java_this)->Intern();
return soa.AddLocalReference<jstring>(result);
}
static void String_setCharAt(JNIEnv* env, jobject java_this, jint index, jchar c) {
ScopedFastNativeObjectAccess soa(env);
- soa.Decode<mirror::String*>(java_this)->SetCharAt(index, c);
+ soa.Decode<mirror::String>(java_this)->SetCharAt(index, c);
}
static jcharArray String_toCharArray(JNIEnv* env, jobject java_this) {
ScopedFastNativeObjectAccess soa(env);
- mirror::String* s = soa.Decode<mirror::String*>(java_this);
+ ObjPtr<mirror::String> s = soa.Decode<mirror::String>(java_this);
return soa.AddLocalReference<jcharArray>(s->ToCharArray(soa.Self()));
}
diff --git a/runtime/native/java_lang_StringFactory.cc b/runtime/native/java_lang_StringFactory.cc
index 5a219ef..119f2b8 100644
--- a/runtime/native/java_lang_StringFactory.cc
+++ b/runtime/native/java_lang_StringFactory.cc
@@ -20,8 +20,8 @@
#include "jni_internal.h"
#include "mirror/object-inl.h"
#include "mirror/string.h"
-#include "scoped_fast_native_object_access.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_fast_native_object_access-inl.h"
+#include "scoped_thread_state_change-inl.h"
#include "ScopedLocalRef.h"
#include "ScopedPrimitiveArray.h"
@@ -35,7 +35,7 @@
return nullptr;
}
StackHandleScope<1> hs(soa.Self());
- Handle<mirror::ByteArray> byte_array(hs.NewHandle(soa.Decode<mirror::ByteArray*>(java_data)));
+ Handle<mirror::ByteArray> byte_array(hs.NewHandle(soa.Decode<mirror::ByteArray>(java_data)));
int32_t data_size = byte_array->GetLength();
if ((offset | byte_count) < 0 || byte_count > data_size - offset) {
soa.Self()->ThrowNewExceptionF("Ljava/lang/StringIndexOutOfBoundsException;",
@@ -56,7 +56,7 @@
DCHECK(java_data != nullptr);
ScopedFastNativeObjectAccess soa(env);
StackHandleScope<1> hs(soa.Self());
- Handle<mirror::CharArray> char_array(hs.NewHandle(soa.Decode<mirror::CharArray*>(java_data)));
+ Handle<mirror::CharArray> char_array(hs.NewHandle(soa.Decode<mirror::CharArray>(java_data)));
gc::AllocatorType allocator_type = Runtime::Current()->GetHeap()->GetCurrentAllocator();
mirror::String* result = mirror::String::AllocFromCharArray<true>(soa.Self(), char_count,
char_array, offset,
@@ -71,7 +71,7 @@
return nullptr;
}
StackHandleScope<1> hs(soa.Self());
- Handle<mirror::String> string(hs.NewHandle(soa.Decode<mirror::String*>(to_copy)));
+ Handle<mirror::String> string(hs.NewHandle(soa.Decode<mirror::String>(to_copy)));
gc::AllocatorType allocator_type = Runtime::Current()->GetHeap()->GetCurrentAllocator();
mirror::String* result = mirror::String::AllocFromString<true>(soa.Self(), string->GetLength(),
string, 0, allocator_type);
diff --git a/runtime/native/java_lang_System.cc b/runtime/native/java_lang_System.cc
index 1b399aa..8b9d0c7 100644
--- a/runtime/native/java_lang_System.cc
+++ b/runtime/native/java_lang_System.cc
@@ -24,7 +24,7 @@
#include "mirror/class-inl.h"
#include "mirror/object-inl.h"
#include "mirror/object_array-inl.h"
-#include "scoped_fast_native_object_access.h"
+#include "scoped_fast_native_object_access-inl.h"
namespace art {
@@ -60,14 +60,14 @@
}
// Make sure source and destination are both arrays.
- mirror::Object* srcObject = soa.Decode<mirror::Object*>(javaSrc);
+ ObjPtr<mirror::Object> srcObject = soa.Decode<mirror::Object>(javaSrc);
if (UNLIKELY(!srcObject->IsArrayInstance())) {
- ThrowArrayStoreException_NotAnArray("source", srcObject);
+ ThrowArrayStoreException_NotAnArray("source", srcObject.Decode());
return;
}
- mirror::Object* dstObject = soa.Decode<mirror::Object*>(javaDst);
+ ObjPtr<mirror::Object> dstObject = soa.Decode<mirror::Object>(javaDst);
if (UNLIKELY(!dstObject->IsArrayInstance())) {
- ThrowArrayStoreException_NotAnArray("destination", dstObject);
+ ThrowArrayStoreException_NotAnArray("destination", dstObject.Decode());
return;
}
mirror::Array* srcArray = srcObject->AsArray();
@@ -164,8 +164,8 @@
inline void System_arraycopyTUnchecked(JNIEnv* env, jobject javaSrc, jint srcPos,
jobject javaDst, jint dstPos, jint count) {
ScopedFastNativeObjectAccess soa(env);
- mirror::Object* srcObject = soa.Decode<mirror::Object*>(javaSrc);
- mirror::Object* dstObject = soa.Decode<mirror::Object*>(javaDst);
+ ObjPtr<mirror::Object> srcObject = soa.Decode<mirror::Object>(javaSrc);
+ ObjPtr<mirror::Object> dstObject = soa.Decode<mirror::Object>(javaDst);
DCHECK(dstObject != nullptr);
mirror::Array* srcArray = srcObject->AsArray();
mirror::Array* dstArray = dstObject->AsArray();
@@ -228,7 +228,7 @@
return 0;
}
ScopedFastNativeObjectAccess soa(env);
- mirror::Object* o = soa.Decode<mirror::Object*>(javaObject);
+ ObjPtr<mirror::Object> o = soa.Decode<mirror::Object>(javaObject);
return static_cast<jint>(o->IdentityHashCode());
}
diff --git a/runtime/native/java_lang_Thread.cc b/runtime/native/java_lang_Thread.cc
index a742e81..0635261 100644
--- a/runtime/native/java_lang_Thread.cc
+++ b/runtime/native/java_lang_Thread.cc
@@ -20,8 +20,8 @@
#include "jni_internal.h"
#include "monitor.h"
#include "mirror/object.h"
-#include "scoped_fast_native_object_access.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_fast_native_object_access-inl.h"
+#include "scoped_thread_state_change-inl.h"
#include "ScopedUtfChars.h"
#include "thread.h"
#include "thread_list.h"
@@ -109,14 +109,14 @@
static jboolean Thread_nativeHoldsLock(JNIEnv* env, jobject java_thread, jobject java_object) {
ScopedObjectAccess soa(env);
- mirror::Object* object = soa.Decode<mirror::Object*>(java_object);
+ ObjPtr<mirror::Object> object = soa.Decode<mirror::Object>(java_object);
if (object == nullptr) {
ThrowNullPointerException("object == null");
return JNI_FALSE;
}
MutexLock mu(soa.Self(), *Locks::thread_list_lock_);
Thread* thread = Thread::FromManagedThread(soa, java_thread);
- return thread->HoldsLock(object);
+ return thread->HoldsLock(object.Decode());
}
static void Thread_nativeInterrupt(JNIEnv* env, jobject java_thread) {
@@ -132,7 +132,7 @@
ScopedUtfChars name(env, java_name);
{
ScopedObjectAccess soa(env);
- if (soa.Decode<mirror::Object*>(peer) == soa.Self()->GetPeer()) {
+ if (soa.Decode<mirror::Object>(peer) == soa.Self()->GetPeer()) {
soa.Self()->SetThreadName(name.c_str());
return;
}
@@ -172,8 +172,8 @@
static void Thread_sleep(JNIEnv* env, jclass, jobject java_lock, jlong ms, jint ns) {
ScopedFastNativeObjectAccess soa(env);
- mirror::Object* lock = soa.Decode<mirror::Object*>(java_lock);
- Monitor::Wait(Thread::Current(), lock, ms, ns, true, kSleeping);
+ ObjPtr<mirror::Object> lock = soa.Decode<mirror::Object>(java_lock);
+ Monitor::Wait(Thread::Current(), lock.Decode(), ms, ns, true, kSleeping);
}
/*
diff --git a/runtime/native/java_lang_Throwable.cc b/runtime/native/java_lang_Throwable.cc
index cb8a869..ff3e044 100644
--- a/runtime/native/java_lang_Throwable.cc
+++ b/runtime/native/java_lang_Throwable.cc
@@ -17,7 +17,7 @@
#include "java_lang_Throwable.h"
#include "jni_internal.h"
-#include "scoped_fast_native_object_access.h"
+#include "scoped_fast_native_object_access-inl.h"
#include "thread.h"
namespace art {
diff --git a/runtime/native/java_lang_VMClassLoader.cc b/runtime/native/java_lang_VMClassLoader.cc
index 6f735aa..0694c4d 100644
--- a/runtime/native/java_lang_VMClassLoader.cc
+++ b/runtime/native/java_lang_VMClassLoader.cc
@@ -20,7 +20,7 @@
#include "jni_internal.h"
#include "mirror/class_loader.h"
#include "mirror/object-inl.h"
-#include "scoped_fast_native_object_access.h"
+#include "scoped_fast_native_object_access-inl.h"
#include "ScopedUtfChars.h"
#include "zip_archive.h"
@@ -29,7 +29,7 @@
static jclass VMClassLoader_findLoadedClass(JNIEnv* env, jclass, jobject javaLoader,
jstring javaName) {
ScopedFastNativeObjectAccess soa(env);
- mirror::ClassLoader* loader = soa.Decode<mirror::ClassLoader*>(javaLoader);
+ ObjPtr<mirror::ClassLoader> loader = soa.Decode<mirror::ClassLoader>(javaLoader);
ScopedUtfChars name(env, javaName);
if (name.c_str() == nullptr) {
return nullptr;
@@ -37,7 +37,10 @@
ClassLinker* cl = Runtime::Current()->GetClassLinker();
std::string descriptor(DotToDescriptor(name.c_str()));
const size_t descriptor_hash = ComputeModifiedUtf8Hash(descriptor.c_str());
- mirror::Class* c = cl->LookupClass(soa.Self(), descriptor.c_str(), descriptor_hash, loader);
+ mirror::Class* c = cl->LookupClass(soa.Self(),
+ descriptor.c_str(),
+ descriptor_hash,
+ loader.Decode());
if (c != nullptr && c->IsResolved()) {
return soa.AddLocalReference<jclass>(c);
}
diff --git a/runtime/native/java_lang_ref_FinalizerReference.cc b/runtime/native/java_lang_ref_FinalizerReference.cc
index 0532c35..08bcc38 100644
--- a/runtime/native/java_lang_ref_FinalizerReference.cc
+++ b/runtime/native/java_lang_ref_FinalizerReference.cc
@@ -21,14 +21,15 @@
#include "jni_internal.h"
#include "mirror/object-inl.h"
#include "mirror/reference-inl.h"
-#include "scoped_fast_native_object_access.h"
+#include "scoped_fast_native_object_access-inl.h"
namespace art {
static jboolean FinalizerReference_makeCircularListIfUnenqueued(JNIEnv* env, jobject javaThis) {
ScopedFastNativeObjectAccess soa(env);
- mirror::FinalizerReference* const ref = soa.Decode<mirror::FinalizerReference*>(javaThis);
- return Runtime::Current()->GetHeap()->GetReferenceProcessor()->MakeCircularListIfUnenqueued(ref);
+ ObjPtr<mirror::FinalizerReference> ref = soa.Decode<mirror::FinalizerReference>(javaThis);
+ return Runtime::Current()->GetHeap()->GetReferenceProcessor()->MakeCircularListIfUnenqueued(
+ ref.Decode());
}
static JNINativeMethod gMethods[] = {
diff --git a/runtime/native/java_lang_ref_Reference.cc b/runtime/native/java_lang_ref_Reference.cc
index d232059..9a088ed 100644
--- a/runtime/native/java_lang_ref_Reference.cc
+++ b/runtime/native/java_lang_ref_Reference.cc
@@ -21,15 +21,15 @@
#include "jni_internal.h"
#include "mirror/object-inl.h"
#include "mirror/reference-inl.h"
-#include "scoped_fast_native_object_access.h"
+#include "scoped_fast_native_object_access-inl.h"
namespace art {
static jobject Reference_getReferent(JNIEnv* env, jobject javaThis) {
ScopedFastNativeObjectAccess soa(env);
- mirror::Reference* const ref = soa.Decode<mirror::Reference*>(javaThis);
+ ObjPtr<mirror::Reference> ref = soa.Decode<mirror::Reference>(javaThis);
mirror::Object* const referent =
- Runtime::Current()->GetHeap()->GetReferenceProcessor()->GetReferent(soa.Self(), ref);
+ Runtime::Current()->GetHeap()->GetReferenceProcessor()->GetReferent(soa.Self(), ref.Decode());
return soa.AddLocalReference<jobject>(referent);
}
diff --git a/runtime/native/java_lang_reflect_Array.cc b/runtime/native/java_lang_reflect_Array.cc
index beb953b..3718ce8 100644
--- a/runtime/native/java_lang_reflect_Array.cc
+++ b/runtime/native/java_lang_reflect_Array.cc
@@ -22,7 +22,7 @@
#include "jni_internal.h"
#include "mirror/class-inl.h"
#include "mirror/object-inl.h"
-#include "scoped_fast_native_object_access.h"
+#include "scoped_fast_native_object_access-inl.h"
#include "handle_scope-inl.h"
namespace art {
@@ -32,15 +32,15 @@
ScopedFastNativeObjectAccess soa(env);
DCHECK(javaElementClass != nullptr);
StackHandleScope<2> hs(soa.Self());
- Handle<mirror::Class> element_class(hs.NewHandle(soa.Decode<mirror::Class*>(javaElementClass)));
+ Handle<mirror::Class> element_class(hs.NewHandle(soa.Decode<mirror::Class>(javaElementClass)));
DCHECK(element_class->IsClass());
DCHECK(javaDimArray != nullptr);
- mirror::Object* dimensions_obj = soa.Decode<mirror::Object*>(javaDimArray);
+ ObjPtr<mirror::Object> dimensions_obj = soa.Decode<mirror::Object>(javaDimArray);
DCHECK(dimensions_obj->IsArrayInstance());
DCHECK_EQ(dimensions_obj->GetClass()->GetComponentType()->GetPrimitiveType(),
Primitive::kPrimInt);
Handle<mirror::IntArray> dimensions_array(
- hs.NewHandle(down_cast<mirror::IntArray*>(dimensions_obj)));
+ hs.NewHandle(down_cast<mirror::IntArray*>(dimensions_obj.Decode())));
mirror::Array* new_array = mirror::Array::CreateMultiArray(soa.Self(), element_class,
dimensions_array);
return soa.AddLocalReference<jobject>(new_array);
@@ -53,7 +53,7 @@
ThrowNegativeArraySizeException(length);
return nullptr;
}
- mirror::Class* element_class = soa.Decode<mirror::Class*>(javaElementClass);
+ mirror::Class* element_class = soa.Decode<mirror::Class>(javaElementClass).Decode();
Runtime* runtime = Runtime::Current();
ClassLinker* class_linker = runtime->GetClassLinker();
mirror::Class* array_class = class_linker->FindArrayClass(soa.Self(), &element_class);
diff --git a/runtime/native/java_lang_reflect_Constructor.cc b/runtime/native/java_lang_reflect_Constructor.cc
index d001d0c..7de0147 100644
--- a/runtime/native/java_lang_reflect_Constructor.cc
+++ b/runtime/native/java_lang_reflect_Constructor.cc
@@ -26,7 +26,7 @@
#include "mirror/method.h"
#include "mirror/object-inl.h"
#include "reflection.h"
-#include "scoped_fast_native_object_access.h"
+#include "scoped_fast_native_object_access-inl.h"
#include "well_known_classes.h"
namespace art {
@@ -60,7 +60,7 @@
*/
static jobject Constructor_newInstance0(JNIEnv* env, jobject javaMethod, jobjectArray javaArgs) {
ScopedFastNativeObjectAccess soa(env);
- mirror::Constructor* m = soa.Decode<mirror::Constructor*>(javaMethod);
+ ObjPtr<mirror::Constructor> m = soa.Decode<mirror::Constructor>(javaMethod);
StackHandleScope<1> hs(soa.Self());
Handle<mirror::Class> c(hs.NewHandle(m->GetDeclaringClass()));
if (UNLIKELY(c->IsAbstract())) {
@@ -73,7 +73,7 @@
if (!m->IsAccessible() && !c->IsPublic()) {
// Go 2 frames back, this method is always called from newInstance0, which is called from
// Constructor.newInstance(Object... args).
- auto* caller = GetCallingClass(soa.Self(), 2);
+ ObjPtr<mirror::Class> caller = GetCallingClass(soa.Self(), 2);
// If caller is null, then we called from JNI, just avoid the check since JNI avoids most
// access checks anyways. TODO: Investigate if this the correct behavior.
if (caller != nullptr && !caller->CanAccess(c.Get())) {
diff --git a/runtime/native/java_lang_reflect_Executable.cc b/runtime/native/java_lang_reflect_Executable.cc
index f345c09..c7c8008 100644
--- a/runtime/native/java_lang_reflect_Executable.cc
+++ b/runtime/native/java_lang_reflect_Executable.cc
@@ -25,7 +25,7 @@
#include "mirror/object-inl.h"
#include "mirror/object_array-inl.h"
#include "reflection.h"
-#include "scoped_fast_native_object_access.h"
+#include "scoped_fast_native_object_access-inl.h"
#include "well_known_classes.h"
namespace art {
@@ -35,10 +35,10 @@
ArtMethod* method = ArtMethod::FromReflectedMethod(soa, javaMethod);
if (method->GetDeclaringClass()->IsProxyClass()) {
// Return an empty array instead of a null pointer.
- mirror::Class* annotation_array_class =
- soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_annotation_Annotation__array);
- mirror::ObjectArray<mirror::Object>* empty_array =
- mirror::ObjectArray<mirror::Object>::Alloc(soa.Self(), annotation_array_class, 0);
+ ObjPtr<mirror::Class> annotation_array_class =
+ soa.Decode<mirror::Class>(WellKnownClasses::java_lang_annotation_Annotation__array);
+ ObjPtr<mirror::ObjectArray<mirror::Object>> empty_array =
+ mirror::ObjectArray<mirror::Object>::Alloc(soa.Self(), annotation_array_class.Decode(), 0);
return soa.AddLocalReference<jobjectArray>(empty_array);
}
return soa.AddLocalReference<jobjectArray>(annotations::GetAnnotationsForMethod(method));
@@ -53,7 +53,7 @@
if (method->IsProxyMethod()) {
return nullptr;
} else {
- Handle<mirror::Class> klass(hs.NewHandle(soa.Decode<mirror::Class*>(annotationType)));
+ Handle<mirror::Class> klass(hs.NewHandle(soa.Decode<mirror::Class>(annotationType)));
return soa.AddLocalReference<jobject>(annotations::GetAnnotationForMethod(method, klass));
}
}
@@ -84,7 +84,7 @@
Thread* self = soa.Self();
StackHandleScope<8> hs(self);
- Handle<mirror::Method> executable = hs.NewHandle(soa.Decode<mirror::Method*>(javaMethod));
+ Handle<mirror::Method> executable = hs.NewHandle(soa.Decode<mirror::Method>(javaMethod));
ArtMethod* art_method = executable.Get()->GetArtMethod();
if (art_method->GetDeclaringClass()->IsProxyClass()) {
return nullptr;
@@ -122,7 +122,7 @@
// Instantiate a Parameter[] to hold the result.
Handle<mirror::Class> parameter_array_class =
hs.NewHandle(
- soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_reflect_Parameter__array));
+ soa.Decode<mirror::Class>(WellKnownClasses::java_lang_reflect_Parameter__array));
Handle<mirror::ObjectArray<mirror::Object>> parameter_array =
hs.NewHandle(
mirror::ObjectArray<mirror::Object>::Alloc(self,
@@ -134,7 +134,7 @@
}
Handle<mirror::Class> parameter_class =
- hs.NewHandle(soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_reflect_Parameter));
+ hs.NewHandle(soa.Decode<mirror::Class>(WellKnownClasses::java_lang_reflect_Parameter));
ArtMethod* parameter_init =
soa.DecodeMethod(WellKnownClasses::java_lang_reflect_Parameter_init);
@@ -186,7 +186,7 @@
return false;
}
StackHandleScope<1> hs(soa.Self());
- Handle<mirror::Class> klass(hs.NewHandle(soa.Decode<mirror::Class*>(annotationType)));
+ Handle<mirror::Class> klass(hs.NewHandle(soa.Decode<mirror::Class>(annotationType)));
return annotations::IsMethodAnnotationPresent(method, klass);
}
diff --git a/runtime/native/java_lang_reflect_Field.cc b/runtime/native/java_lang_reflect_Field.cc
index 412445f..2519225 100644
--- a/runtime/native/java_lang_reflect_Field.cc
+++ b/runtime/native/java_lang_reflect_Field.cc
@@ -25,7 +25,7 @@
#include "mirror/class-inl.h"
#include "mirror/field.h"
#include "reflection-inl.h"
-#include "scoped_fast_native_object_access.h"
+#include "scoped_fast_native_object_access-inl.h"
#include "utils.h"
namespace art {
@@ -43,9 +43,13 @@
PrettyClass(field->GetDeclaringClass()).c_str()).c_str());
return false;
}
- mirror::Class* calling_class = nullptr;
- if (!VerifyAccess(self, obj, field->GetDeclaringClass(), field->GetAccessFlags(),
- &calling_class, 1)) {
+ ObjPtr<mirror::Class> calling_class;
+ if (!VerifyAccess(self,
+ MakeObjPtr(obj),
+ MakeObjPtr(field->GetDeclaringClass()),
+ field->GetAccessFlags(),
+ &calling_class,
+ 1)) {
ThrowIllegalAccessException(
StringPrintf("Class %s cannot access %s field %s of class %s",
calling_class == nullptr ? "null" : PrettyClass(calling_class).c_str(),
@@ -123,8 +127,8 @@
*class_or_rcvr = declaringClass;
return true;
}
- *class_or_rcvr = soa.Decode<mirror::Object*>(j_rcvr);
- if (!VerifyObjectIsClass(*class_or_rcvr, declaringClass)) {
+ *class_or_rcvr = soa.Decode<mirror::Object>(j_rcvr).Decode();
+ if (!VerifyObjectIsClass(MakeObjPtr(*class_or_rcvr), MakeObjPtr(declaringClass))) {
DCHECK(soa.Self()->IsExceptionPending());
return false;
}
@@ -133,7 +137,7 @@
static jobject Field_get(JNIEnv* env, jobject javaField, jobject javaObj) {
ScopedFastNativeObjectAccess soa(env);
- mirror::Field* f = soa.Decode<mirror::Field*>(javaField);
+ mirror::Field* f = soa.Decode<mirror::Field>(javaField).Decode();
mirror::Object* o = nullptr;
if (!CheckReceiver(soa, javaObj, &f, &o)) {
DCHECK(soa.Self()->IsExceptionPending());
@@ -152,14 +156,14 @@
DCHECK(soa.Self()->IsExceptionPending());
return nullptr;
}
- return soa.AddLocalReference<jobject>(BoxPrimitive(field_type, value));
+ return soa.AddLocalReference<jobject>(BoxPrimitive(field_type, value).Decode());
}
template<Primitive::Type kPrimitiveType>
ALWAYS_INLINE inline static JValue GetPrimitiveField(JNIEnv* env, jobject javaField,
jobject javaObj) {
ScopedFastNativeObjectAccess soa(env);
- mirror::Field* f = soa.Decode<mirror::Field*>(javaField);
+ mirror::Field* f = soa.Decode<mirror::Field>(javaField).Decode();
mirror::Object* o = nullptr;
if (!CheckReceiver(soa, javaObj, &f, &o)) {
DCHECK(soa.Self()->IsExceptionPending());
@@ -303,7 +307,7 @@
static void Field_set(JNIEnv* env, jobject javaField, jobject javaObj, jobject javaValue) {
ScopedFastNativeObjectAccess soa(env);
- mirror::Field* f = soa.Decode<mirror::Field*>(javaField);
+ mirror::Field* f = soa.Decode<mirror::Field>(javaField).Decode();
// Check that the receiver is non-null and an instance of the field's declaring class.
mirror::Object* o = nullptr;
if (!CheckReceiver(soa, javaObj, &f, &o)) {
@@ -321,9 +325,12 @@
}
// We now don't expect suspension unless an exception is thrown.
// Unbox the value, if necessary.
- mirror::Object* boxed_value = soa.Decode<mirror::Object*>(javaValue);
+ ObjPtr<mirror::Object> boxed_value = soa.Decode<mirror::Object>(javaValue);
JValue unboxed_value;
- if (!UnboxPrimitiveForField(boxed_value, field_type, f->GetArtField(), &unboxed_value)) {
+ if (!UnboxPrimitiveForField(boxed_value,
+ MakeObjPtr(field_type),
+ f->GetArtField(),
+ &unboxed_value)) {
DCHECK(soa.Self()->IsExceptionPending());
return;
}
@@ -339,7 +346,7 @@
static void SetPrimitiveField(JNIEnv* env, jobject javaField, jobject javaObj,
const JValue& new_value) {
ScopedFastNativeObjectAccess soa(env);
- mirror::Field* f = soa.Decode<mirror::Field*>(javaField);
+ mirror::Field* f = soa.Decode<mirror::Field>(javaField).Decode();
mirror::Object* o = nullptr;
if (!CheckReceiver(soa, javaObj, &f, &o)) {
return;
@@ -419,21 +426,22 @@
static jobject Field_getAnnotationNative(JNIEnv* env, jobject javaField, jclass annotationType) {
ScopedFastNativeObjectAccess soa(env);
StackHandleScope<1> hs(soa.Self());
- ArtField* field = soa.Decode<mirror::Field*>(javaField)->GetArtField();
+ ArtField* field = soa.Decode<mirror::Field>(javaField)->GetArtField();
if (field->GetDeclaringClass()->IsProxyClass()) {
return nullptr;
}
- Handle<mirror::Class> klass(hs.NewHandle(soa.Decode<mirror::Class*>(annotationType)));
+ Handle<mirror::Class> klass(hs.NewHandle(soa.Decode<mirror::Class>(annotationType)));
return soa.AddLocalReference<jobject>(annotations::GetAnnotationForField(field, klass));
}
static jobjectArray Field_getDeclaredAnnotations(JNIEnv* env, jobject javaField) {
ScopedFastNativeObjectAccess soa(env);
- ArtField* field = soa.Decode<mirror::Field*>(javaField)->GetArtField();
+ ArtField* field = soa.Decode<mirror::Field>(javaField)->GetArtField();
if (field->GetDeclaringClass()->IsProxyClass()) {
// Return an empty array instead of a null pointer.
mirror::Class* annotation_array_class =
- soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_annotation_Annotation__array);
+ soa.Decode<mirror::Class>(
+ WellKnownClasses::java_lang_annotation_Annotation__array).Decode();
mirror::ObjectArray<mirror::Object>* empty_array =
mirror::ObjectArray<mirror::Object>::Alloc(soa.Self(), annotation_array_class, 0);
return soa.AddLocalReference<jobjectArray>(empty_array);
@@ -443,7 +451,7 @@
static jobjectArray Field_getSignatureAnnotation(JNIEnv* env, jobject javaField) {
ScopedFastNativeObjectAccess soa(env);
- ArtField* field = soa.Decode<mirror::Field*>(javaField)->GetArtField();
+ ArtField* field = soa.Decode<mirror::Field>(javaField)->GetArtField();
if (field->GetDeclaringClass()->IsProxyClass()) {
return nullptr;
}
@@ -454,11 +462,11 @@
jclass annotationType) {
ScopedFastNativeObjectAccess soa(env);
StackHandleScope<1> hs(soa.Self());
- ArtField* field = soa.Decode<mirror::Field*>(javaField)->GetArtField();
+ ArtField* field = soa.Decode<mirror::Field>(javaField)->GetArtField();
if (field->GetDeclaringClass()->IsProxyClass()) {
return false;
}
- Handle<mirror::Class> klass(hs.NewHandle(soa.Decode<mirror::Class*>(annotationType)));
+ Handle<mirror::Class> klass(hs.NewHandle(soa.Decode<mirror::Class>(annotationType)));
return annotations::IsFieldAnnotationPresent(field, klass);
}
diff --git a/runtime/native/java_lang_reflect_Method.cc b/runtime/native/java_lang_reflect_Method.cc
index b8efb14..b5f2f7c 100644
--- a/runtime/native/java_lang_reflect_Method.cc
+++ b/runtime/native/java_lang_reflect_Method.cc
@@ -26,7 +26,7 @@
#include "mirror/object-inl.h"
#include "mirror/object_array-inl.h"
#include "reflection.h"
-#include "scoped_fast_native_object_access.h"
+#include "scoped_fast_native_object_access-inl.h"
#include "well_known_classes.h"
namespace art {
diff --git a/runtime/native/java_lang_reflect_Parameter.cc b/runtime/native/java_lang_reflect_Parameter.cc
index c2a803c..6060b8a 100644
--- a/runtime/native/java_lang_reflect_Parameter.cc
+++ b/runtime/native/java_lang_reflect_Parameter.cc
@@ -21,7 +21,7 @@
#include "dex_file-inl.h"
#include "dex_file_annotations.h"
#include "jni_internal.h"
-#include "scoped_fast_native_object_access.h"
+#include "scoped_fast_native_object_access-inl.h"
#include "utils.h"
namespace art {
@@ -53,7 +53,7 @@
}
StackHandleScope<1> hs(soa.Self());
- Handle<mirror::Class> klass(hs.NewHandle(soa.Decode<mirror::Class*>(annotationType)));
+ Handle<mirror::Class> klass(hs.NewHandle(soa.Decode<mirror::Class>(annotationType)));
return soa.AddLocalReference<jobject>(
annotations::GetAnnotationForMethodParameter(method, parameterIndex, klass));
}
diff --git a/runtime/native/java_lang_reflect_Proxy.cc b/runtime/native/java_lang_reflect_Proxy.cc
index 4a6ab40..ece0338 100644
--- a/runtime/native/java_lang_reflect_Proxy.cc
+++ b/runtime/native/java_lang_reflect_Proxy.cc
@@ -21,7 +21,7 @@
#include "mirror/class_loader.h"
#include "mirror/object_array.h"
#include "mirror/string.h"
-#include "scoped_fast_native_object_access.h"
+#include "scoped_fast_native_object_access-inl.h"
#include "verify_object-inl.h"
namespace art {
diff --git a/runtime/native/libcore_util_CharsetUtils.cc b/runtime/native/libcore_util_CharsetUtils.cc
index 64d56f6..2590452 100644
--- a/runtime/native/libcore_util_CharsetUtils.cc
+++ b/runtime/native/libcore_util_CharsetUtils.cc
@@ -18,7 +18,7 @@
#include "mirror/string.h"
#include "mirror/string-inl.h"
#include "native/libcore_util_CharsetUtils.h"
-#include "scoped_fast_native_object_access.h"
+#include "scoped_fast_native_object_access-inl.h"
#include "ScopedPrimitiveArray.h"
#include "unicode/utf16.h"
@@ -154,7 +154,7 @@
jchar maxValidChar) {
ScopedObjectAccess soa(env);
StackHandleScope<1> hs(soa.Self());
- Handle<mirror::String> string(hs.NewHandle(soa.Decode<mirror::String*>(java_string)));
+ Handle<mirror::String> string(hs.NewHandle(soa.Decode<mirror::String>(java_string)));
if (string.Get() == nullptr) {
return nullptr;
}
@@ -191,7 +191,7 @@
jint length) {
ScopedObjectAccess soa(env);
StackHandleScope<1> hs(soa.Self());
- Handle<mirror::String> string(hs.NewHandle(soa.Decode<mirror::String*>(java_string)));
+ Handle<mirror::String> string(hs.NewHandle(soa.Decode<mirror::String>(java_string)));
if (string.Get() == nullptr) {
return nullptr;
}
diff --git a/runtime/native/org_apache_harmony_dalvik_ddmc_DdmServer.cc b/runtime/native/org_apache_harmony_dalvik_ddmc_DdmServer.cc
index 0ab2979..5356498 100644
--- a/runtime/native/org_apache_harmony_dalvik_ddmc_DdmServer.cc
+++ b/runtime/native/org_apache_harmony_dalvik_ddmc_DdmServer.cc
@@ -19,7 +19,7 @@
#include "base/logging.h"
#include "debugger.h"
#include "jni_internal.h"
-#include "scoped_fast_native_object_access.h"
+#include "scoped_fast_native_object_access-inl.h"
#include "ScopedPrimitiveArray.h"
namespace art {
diff --git a/runtime/native/org_apache_harmony_dalvik_ddmc_DdmVmInternal.cc b/runtime/native/org_apache_harmony_dalvik_ddmc_DdmVmInternal.cc
index 9ed0e7e..ca17c26 100644
--- a/runtime/native/org_apache_harmony_dalvik_ddmc_DdmVmInternal.cc
+++ b/runtime/native/org_apache_harmony_dalvik_ddmc_DdmVmInternal.cc
@@ -20,7 +20,7 @@
#include "base/mutex.h"
#include "debugger.h"
#include "jni_internal.h"
-#include "scoped_fast_native_object_access.h"
+#include "scoped_fast_native_object_access-inl.h"
#include "ScopedLocalRef.h"
#include "ScopedPrimitiveArray.h"
#include "thread_list.h"
diff --git a/runtime/native/scoped_fast_native_object_access-inl.h b/runtime/native/scoped_fast_native_object_access-inl.h
new file mode 100644
index 0000000..1d73813
--- /dev/null
+++ b/runtime/native/scoped_fast_native_object_access-inl.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_RUNTIME_NATIVE_SCOPED_FAST_NATIVE_OBJECT_ACCESS_INL_H_
+#define ART_RUNTIME_NATIVE_SCOPED_FAST_NATIVE_OBJECT_ACCESS_INL_H_
+
+#include "scoped_fast_native_object_access.h"
+
+#include "art_method-inl.h"
+#include "scoped_thread_state_change-inl.h"
+
+namespace art {
+
+inline ScopedFastNativeObjectAccess::ScopedFastNativeObjectAccess(JNIEnv* env)
+ : ScopedObjectAccessAlreadyRunnable(env) {
+ Locks::mutator_lock_->AssertSharedHeld(Self());
+ DCHECK((*Self()->GetManagedStack()->GetTopQuickFrame())->IsFastNative());
+ // Don't work with raw objects in non-runnable states.
+ DCHECK_EQ(Self()->GetState(), kRunnable);
+}
+
+} // namespace art
+
+#endif // ART_RUNTIME_NATIVE_SCOPED_FAST_NATIVE_OBJECT_ACCESS_INL_H_
diff --git a/runtime/native/scoped_fast_native_object_access.h b/runtime/native/scoped_fast_native_object_access.h
index c4a33df..6a9365d 100644
--- a/runtime/native/scoped_fast_native_object_access.h
+++ b/runtime/native/scoped_fast_native_object_access.h
@@ -17,7 +17,8 @@
#ifndef ART_RUNTIME_NATIVE_SCOPED_FAST_NATIVE_OBJECT_ACCESS_H_
#define ART_RUNTIME_NATIVE_SCOPED_FAST_NATIVE_OBJECT_ACCESS_H_
-#include "art_method-inl.h"
+#include <jni.h>
+
#include "scoped_thread_state_change.h"
namespace art {
@@ -26,18 +27,11 @@
// JNI methods.
class ScopedFastNativeObjectAccess : public ScopedObjectAccessAlreadyRunnable {
public:
- explicit ScopedFastNativeObjectAccess(JNIEnv* env)
+ ALWAYS_INLINE explicit ScopedFastNativeObjectAccess(JNIEnv* env)
REQUIRES(!Locks::thread_suspend_count_lock_)
- SHARED_LOCK_FUNCTION(Locks::mutator_lock_) ALWAYS_INLINE
- : ScopedObjectAccessAlreadyRunnable(env) {
- Locks::mutator_lock_->AssertSharedHeld(Self());
- DCHECK((*Self()->GetManagedStack()->GetTopQuickFrame())->IsFastNative());
- // Don't work with raw objects in non-runnable states.
- DCHECK_EQ(Self()->GetState(), kRunnable);
- }
+ SHARED_LOCK_FUNCTION(Locks::mutator_lock_);
- ~ScopedFastNativeObjectAccess() UNLOCK_FUNCTION(Locks::mutator_lock_) ALWAYS_INLINE {
- }
+ ALWAYS_INLINE ~ScopedFastNativeObjectAccess() UNLOCK_FUNCTION(Locks::mutator_lock_) {}
private:
DISALLOW_COPY_AND_ASSIGN(ScopedFastNativeObjectAccess);
diff --git a/runtime/native/sun_misc_Unsafe.cc b/runtime/native/sun_misc_Unsafe.cc
index 472340c..2fae3cc 100644
--- a/runtime/native/sun_misc_Unsafe.cc
+++ b/runtime/native/sun_misc_Unsafe.cc
@@ -21,7 +21,7 @@
#include "mirror/array.h"
#include "mirror/class-inl.h"
#include "mirror/object-inl.h"
-#include "scoped_fast_native_object_access.h"
+#include "scoped_fast_native_object_access-inl.h"
#include <unistd.h>
#include <stdlib.h>
@@ -33,61 +33,64 @@
static jboolean Unsafe_compareAndSwapInt(JNIEnv* env, jobject, jobject javaObj, jlong offset,
jint expectedValue, jint newValue) {
ScopedFastNativeObjectAccess soa(env);
- mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
+ ObjPtr<mirror::Object> obj = soa.Decode<mirror::Object>(javaObj);
// JNI must use non transactional mode.
bool success = obj->CasFieldStrongSequentiallyConsistent32<false>(MemberOffset(offset),
- expectedValue, newValue);
+ expectedValue,
+ newValue);
return success ? JNI_TRUE : JNI_FALSE;
}
static jboolean Unsafe_compareAndSwapLong(JNIEnv* env, jobject, jobject javaObj, jlong offset,
jlong expectedValue, jlong newValue) {
ScopedFastNativeObjectAccess soa(env);
- mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
+ ObjPtr<mirror::Object> obj = soa.Decode<mirror::Object>(javaObj);
// JNI must use non transactional mode.
bool success = obj->CasFieldStrongSequentiallyConsistent64<false>(MemberOffset(offset),
- expectedValue, newValue);
+ expectedValue,
+ newValue);
return success ? JNI_TRUE : JNI_FALSE;
}
static jboolean Unsafe_compareAndSwapObject(JNIEnv* env, jobject, jobject javaObj, jlong offset,
jobject javaExpectedValue, jobject javaNewValue) {
ScopedFastNativeObjectAccess soa(env);
- mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
- mirror::Object* expectedValue = soa.Decode<mirror::Object*>(javaExpectedValue);
- mirror::Object* newValue = soa.Decode<mirror::Object*>(javaNewValue);
+ ObjPtr<mirror::Object> obj = soa.Decode<mirror::Object>(javaObj);
+ ObjPtr<mirror::Object> expectedValue = soa.Decode<mirror::Object>(javaExpectedValue);
+ ObjPtr<mirror::Object> newValue = soa.Decode<mirror::Object>(javaNewValue);
// JNI must use non transactional mode.
if (kUseReadBarrier) {
// Need to make sure the reference stored in the field is a to-space one before attempting the
// CAS or the CAS could fail incorrectly.
mirror::HeapReference<mirror::Object>* field_addr =
reinterpret_cast<mirror::HeapReference<mirror::Object>*>(
- reinterpret_cast<uint8_t*>(obj) + static_cast<size_t>(offset));
+ reinterpret_cast<uint8_t*>(obj.Decode()) + static_cast<size_t>(offset));
ReadBarrier::Barrier<mirror::Object, kWithReadBarrier, /*kAlwaysUpdateField*/true>(
- obj,
+ obj.Decode(),
MemberOffset(offset),
field_addr);
}
bool success = obj->CasFieldStrongSequentiallyConsistentObject<false>(MemberOffset(offset),
- expectedValue, newValue);
+ expectedValue.Decode(),
+ newValue.Decode());
return success ? JNI_TRUE : JNI_FALSE;
}
static jint Unsafe_getInt(JNIEnv* env, jobject, jobject javaObj, jlong offset) {
ScopedFastNativeObjectAccess soa(env);
- mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
+ ObjPtr<mirror::Object> obj = soa.Decode<mirror::Object>(javaObj);
return obj->GetField32(MemberOffset(offset));
}
static jint Unsafe_getIntVolatile(JNIEnv* env, jobject, jobject javaObj, jlong offset) {
ScopedFastNativeObjectAccess soa(env);
- mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
+ ObjPtr<mirror::Object> obj = soa.Decode<mirror::Object>(javaObj);
return obj->GetField32Volatile(MemberOffset(offset));
}
static void Unsafe_putInt(JNIEnv* env, jobject, jobject javaObj, jlong offset, jint newValue) {
ScopedFastNativeObjectAccess soa(env);
- mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
+ ObjPtr<mirror::Object> obj = soa.Decode<mirror::Object>(javaObj);
// JNI must use non transactional mode.
obj->SetField32<false>(MemberOffset(offset), newValue);
}
@@ -95,7 +98,7 @@
static void Unsafe_putIntVolatile(JNIEnv* env, jobject, jobject javaObj, jlong offset,
jint newValue) {
ScopedFastNativeObjectAccess soa(env);
- mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
+ ObjPtr<mirror::Object> obj = soa.Decode<mirror::Object>(javaObj);
// JNI must use non transactional mode.
obj->SetField32Volatile<false>(MemberOffset(offset), newValue);
}
@@ -103,7 +106,7 @@
static void Unsafe_putOrderedInt(JNIEnv* env, jobject, jobject javaObj, jlong offset,
jint newValue) {
ScopedFastNativeObjectAccess soa(env);
- mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
+ ObjPtr<mirror::Object> obj = soa.Decode<mirror::Object>(javaObj);
QuasiAtomic::ThreadFenceRelease();
// JNI must use non transactional mode.
obj->SetField32<false>(MemberOffset(offset), newValue);
@@ -111,19 +114,19 @@
static jlong Unsafe_getLong(JNIEnv* env, jobject, jobject javaObj, jlong offset) {
ScopedFastNativeObjectAccess soa(env);
- mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
+ ObjPtr<mirror::Object> obj = soa.Decode<mirror::Object>(javaObj);
return obj->GetField64(MemberOffset(offset));
}
static jlong Unsafe_getLongVolatile(JNIEnv* env, jobject, jobject javaObj, jlong offset) {
ScopedFastNativeObjectAccess soa(env);
- mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
+ ObjPtr<mirror::Object> obj = soa.Decode<mirror::Object>(javaObj);
return obj->GetField64Volatile(MemberOffset(offset));
}
static void Unsafe_putLong(JNIEnv* env, jobject, jobject javaObj, jlong offset, jlong newValue) {
ScopedFastNativeObjectAccess soa(env);
- mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
+ ObjPtr<mirror::Object> obj = soa.Decode<mirror::Object>(javaObj);
// JNI must use non transactional mode.
obj->SetField64<false>(MemberOffset(offset), newValue);
}
@@ -131,7 +134,7 @@
static void Unsafe_putLongVolatile(JNIEnv* env, jobject, jobject javaObj, jlong offset,
jlong newValue) {
ScopedFastNativeObjectAccess soa(env);
- mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
+ ObjPtr<mirror::Object> obj = soa.Decode<mirror::Object>(javaObj);
// JNI must use non transactional mode.
obj->SetField64Volatile<false>(MemberOffset(offset), newValue);
}
@@ -139,7 +142,7 @@
static void Unsafe_putOrderedLong(JNIEnv* env, jobject, jobject javaObj, jlong offset,
jlong newValue) {
ScopedFastNativeObjectAccess soa(env);
- mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
+ ObjPtr<mirror::Object> obj = soa.Decode<mirror::Object>(javaObj);
QuasiAtomic::ThreadFenceRelease();
// JNI must use non transactional mode.
obj->SetField64<false>(MemberOffset(offset), newValue);
@@ -147,56 +150,56 @@
static jobject Unsafe_getObjectVolatile(JNIEnv* env, jobject, jobject javaObj, jlong offset) {
ScopedFastNativeObjectAccess soa(env);
- mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
- mirror::Object* value = obj->GetFieldObjectVolatile<mirror::Object>(MemberOffset(offset));
+ ObjPtr<mirror::Object> obj = soa.Decode<mirror::Object>(javaObj);
+ ObjPtr<mirror::Object> value = obj->GetFieldObjectVolatile<mirror::Object>(MemberOffset(offset));
return soa.AddLocalReference<jobject>(value);
}
static jobject Unsafe_getObject(JNIEnv* env, jobject, jobject javaObj, jlong offset) {
ScopedFastNativeObjectAccess soa(env);
- mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
- mirror::Object* value = obj->GetFieldObject<mirror::Object>(MemberOffset(offset));
+ ObjPtr<mirror::Object> obj = soa.Decode<mirror::Object>(javaObj);
+ ObjPtr<mirror::Object> value = obj->GetFieldObject<mirror::Object>(MemberOffset(offset));
return soa.AddLocalReference<jobject>(value);
}
static void Unsafe_putObject(JNIEnv* env, jobject, jobject javaObj, jlong offset,
jobject javaNewValue) {
ScopedFastNativeObjectAccess soa(env);
- mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
- mirror::Object* newValue = soa.Decode<mirror::Object*>(javaNewValue);
+ ObjPtr<mirror::Object> obj = soa.Decode<mirror::Object>(javaObj);
+ ObjPtr<mirror::Object> newValue = soa.Decode<mirror::Object>(javaNewValue);
// JNI must use non transactional mode.
- obj->SetFieldObject<false>(MemberOffset(offset), newValue);
+ obj->SetFieldObject<false>(MemberOffset(offset), newValue.Decode());
}
static void Unsafe_putObjectVolatile(JNIEnv* env, jobject, jobject javaObj, jlong offset,
jobject javaNewValue) {
ScopedFastNativeObjectAccess soa(env);
- mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
- mirror::Object* newValue = soa.Decode<mirror::Object*>(javaNewValue);
+ ObjPtr<mirror::Object> obj = soa.Decode<mirror::Object>(javaObj);
+ ObjPtr<mirror::Object> newValue = soa.Decode<mirror::Object>(javaNewValue);
// JNI must use non transactional mode.
- obj->SetFieldObjectVolatile<false>(MemberOffset(offset), newValue);
+ obj->SetFieldObjectVolatile<false>(MemberOffset(offset), newValue.Decode());
}
static void Unsafe_putOrderedObject(JNIEnv* env, jobject, jobject javaObj, jlong offset,
jobject javaNewValue) {
ScopedFastNativeObjectAccess soa(env);
- mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
- mirror::Object* newValue = soa.Decode<mirror::Object*>(javaNewValue);
+ ObjPtr<mirror::Object> obj = soa.Decode<mirror::Object>(javaObj);
+ ObjPtr<mirror::Object> newValue = soa.Decode<mirror::Object>(javaNewValue);
QuasiAtomic::ThreadFenceRelease();
// JNI must use non transactional mode.
- obj->SetFieldObject<false>(MemberOffset(offset), newValue);
+ obj->SetFieldObject<false>(MemberOffset(offset), newValue.Decode());
}
static jint Unsafe_getArrayBaseOffsetForComponentType(JNIEnv* env, jclass, jobject component_class) {
ScopedFastNativeObjectAccess soa(env);
- mirror::Class* component = soa.Decode<mirror::Class*>(component_class);
+ ObjPtr<mirror::Class> component = soa.Decode<mirror::Class>(component_class);
Primitive::Type primitive_type = component->GetPrimitiveType();
return mirror::Array::DataOffset(Primitive::ComponentSize(primitive_type)).Int32Value();
}
static jint Unsafe_getArrayIndexScaleForComponentType(JNIEnv* env, jclass, jobject component_class) {
ScopedFastNativeObjectAccess soa(env);
- mirror::Class* component = soa.Decode<mirror::Class*>(component_class);
+ ObjPtr<mirror::Class> component = soa.Decode<mirror::Class>(component_class);
Primitive::Type primitive_type = component->GetPrimitiveType();
return Primitive::ComponentSize(primitive_type);
}
@@ -289,16 +292,16 @@
static void Unsafe_copyMemory(JNIEnv *env, jobject unsafe ATTRIBUTE_UNUSED, jlong src,
jlong dst, jlong size) {
- if (size == 0) {
- return;
- }
- // size is nonnegative and fits into size_t
- if (size < 0 || size != (jlong)(size_t) size) {
- ScopedFastNativeObjectAccess soa(env);
- ThrowIllegalAccessException("wrong number of bytes");
- }
- size_t sz = (size_t)size;
- memcpy(reinterpret_cast<void *>(dst), reinterpret_cast<void *>(src), sz);
+ if (size == 0) {
+ return;
+ }
+ // size is nonnegative and fits into size_t
+ if (size < 0 || size != (jlong)(size_t) size) {
+ ScopedFastNativeObjectAccess soa(env);
+ ThrowIllegalAccessException("wrong number of bytes");
+ }
+ size_t sz = (size_t)size;
+ memcpy(reinterpret_cast<void *>(dst), reinterpret_cast<void *>(src), sz);
}
template<typename T>
@@ -306,12 +309,12 @@
size_t array_offset,
size_t size)
REQUIRES_SHARED(Locks::mutator_lock_) {
- const T* src = reinterpret_cast<T*>(srcAddr);
- size_t sz = size / sizeof(T);
- size_t of = array_offset / sizeof(T);
- for (size_t i = 0; i < sz; ++i) {
- array->Set(i + of, *(src + i));
- }
+ const T* src = reinterpret_cast<T*>(srcAddr);
+ size_t sz = size / sizeof(T);
+ size_t of = array_offset / sizeof(T);
+ for (size_t i = 0; i < sz; ++i) {
+ array->Set(i + of, *(src + i));
+ }
}
template<typename T>
@@ -319,12 +322,12 @@
size_t array_offset,
size_t size)
REQUIRES_SHARED(Locks::mutator_lock_) {
- T* dst = reinterpret_cast<T*>(dstAddr);
- size_t sz = size / sizeof(T);
- size_t of = array_offset / sizeof(T);
- for (size_t i = 0; i < sz; ++i) {
- *(dst + i) = array->Get(i + of);
- }
+ T* dst = reinterpret_cast<T*>(dstAddr);
+ size_t sz = size / sizeof(T);
+ size_t of = array_offset / sizeof(T);
+ for (size_t i = 0; i < sz; ++i) {
+ *(dst + i) = array->Get(i + of);
+ }
}
static void Unsafe_copyMemoryToPrimitiveArray(JNIEnv *env,
@@ -333,29 +336,29 @@
jobject dstObj,
jlong dstOffset,
jlong size) {
- ScopedObjectAccess soa(env);
- if (size == 0) {
- return;
- }
- // size is nonnegative and fits into size_t
- if (size < 0 || size != (jlong)(size_t) size) {
- ThrowIllegalAccessException("wrong number of bytes");
- }
- size_t sz = (size_t)size;
- size_t dst_offset = (size_t)dstOffset;
- mirror::Object* dst = soa.Decode<mirror::Object*>(dstObj);
- mirror::Class* component_type = dst->GetClass()->GetComponentType();
- if (component_type->IsPrimitiveByte() || component_type->IsPrimitiveBoolean()) {
- copyToArray(srcAddr, dst->AsByteSizedArray(), dst_offset, sz);
- } else if (component_type->IsPrimitiveShort() || component_type->IsPrimitiveChar()) {
- copyToArray(srcAddr, dst->AsShortSizedArray(), dst_offset, sz);
- } else if (component_type->IsPrimitiveInt() || component_type->IsPrimitiveFloat()) {
- copyToArray(srcAddr, dst->AsIntArray(), dst_offset, sz);
- } else if (component_type->IsPrimitiveLong() || component_type->IsPrimitiveDouble()) {
- copyToArray(srcAddr, dst->AsLongArray(), dst_offset, sz);
- } else {
- ThrowIllegalAccessException("not a primitive array");
- }
+ ScopedObjectAccess soa(env);
+ if (size == 0) {
+ return;
+ }
+ // size is nonnegative and fits into size_t
+ if (size < 0 || size != (jlong)(size_t) size) {
+ ThrowIllegalAccessException("wrong number of bytes");
+ }
+ size_t sz = (size_t)size;
+ size_t dst_offset = (size_t)dstOffset;
+ ObjPtr<mirror::Object> dst = soa.Decode<mirror::Object>(dstObj);
+ mirror::Class* component_type = dst->GetClass()->GetComponentType();
+ if (component_type->IsPrimitiveByte() || component_type->IsPrimitiveBoolean()) {
+ copyToArray(srcAddr, dst->AsByteSizedArray(), dst_offset, sz);
+ } else if (component_type->IsPrimitiveShort() || component_type->IsPrimitiveChar()) {
+ copyToArray(srcAddr, dst->AsShortSizedArray(), dst_offset, sz);
+ } else if (component_type->IsPrimitiveInt() || component_type->IsPrimitiveFloat()) {
+ copyToArray(srcAddr, dst->AsIntArray(), dst_offset, sz);
+ } else if (component_type->IsPrimitiveLong() || component_type->IsPrimitiveDouble()) {
+ copyToArray(srcAddr, dst->AsLongArray(), dst_offset, sz);
+ } else {
+ ThrowIllegalAccessException("not a primitive array");
+ }
}
static void Unsafe_copyMemoryFromPrimitiveArray(JNIEnv *env,
@@ -364,85 +367,85 @@
jlong srcOffset,
jlong dstAddr,
jlong size) {
- ScopedObjectAccess soa(env);
- if (size == 0) {
- return;
- }
- // size is nonnegative and fits into size_t
- if (size < 0 || size != (jlong)(size_t) size) {
- ThrowIllegalAccessException("wrong number of bytes");
- }
- size_t sz = (size_t)size;
- size_t src_offset = (size_t)srcOffset;
- mirror::Object* src = soa.Decode<mirror::Object*>(srcObj);
- mirror::Class* component_type = src->GetClass()->GetComponentType();
- if (component_type->IsPrimitiveByte() || component_type->IsPrimitiveBoolean()) {
- copyFromArray(dstAddr, src->AsByteSizedArray(), src_offset, sz);
- } else if (component_type->IsPrimitiveShort() || component_type->IsPrimitiveChar()) {
- copyFromArray(dstAddr, src->AsShortSizedArray(), src_offset, sz);
- } else if (component_type->IsPrimitiveInt() || component_type->IsPrimitiveFloat()) {
- copyFromArray(dstAddr, src->AsIntArray(), src_offset, sz);
- } else if (component_type->IsPrimitiveLong() || component_type->IsPrimitiveDouble()) {
- copyFromArray(dstAddr, src->AsLongArray(), src_offset, sz);
- } else {
- ThrowIllegalAccessException("not a primitive array");
- }
+ ScopedObjectAccess soa(env);
+ if (size == 0) {
+ return;
+ }
+ // size is nonnegative and fits into size_t
+ if (size < 0 || size != (jlong)(size_t) size) {
+ ThrowIllegalAccessException("wrong number of bytes");
+ }
+ size_t sz = (size_t)size;
+ size_t src_offset = (size_t)srcOffset;
+ ObjPtr<mirror::Object> src = soa.Decode<mirror::Object>(srcObj);
+ mirror::Class* component_type = src->GetClass()->GetComponentType();
+ if (component_type->IsPrimitiveByte() || component_type->IsPrimitiveBoolean()) {
+ copyFromArray(dstAddr, src->AsByteSizedArray(), src_offset, sz);
+ } else if (component_type->IsPrimitiveShort() || component_type->IsPrimitiveChar()) {
+ copyFromArray(dstAddr, src->AsShortSizedArray(), src_offset, sz);
+ } else if (component_type->IsPrimitiveInt() || component_type->IsPrimitiveFloat()) {
+ copyFromArray(dstAddr, src->AsIntArray(), src_offset, sz);
+ } else if (component_type->IsPrimitiveLong() || component_type->IsPrimitiveDouble()) {
+ copyFromArray(dstAddr, src->AsLongArray(), src_offset, sz);
+ } else {
+ ThrowIllegalAccessException("not a primitive array");
+ }
}
static jboolean Unsafe_getBoolean(JNIEnv* env, jobject, jobject javaObj, jlong offset) {
- ScopedFastNativeObjectAccess soa(env);
- mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
- return obj->GetFieldBoolean(MemberOffset(offset));
+ ScopedFastNativeObjectAccess soa(env);
+ ObjPtr<mirror::Object> obj = soa.Decode<mirror::Object>(javaObj);
+ return obj->GetFieldBoolean(MemberOffset(offset));
}
static void Unsafe_putBoolean(JNIEnv* env, jobject, jobject javaObj, jlong offset, jboolean newValue) {
- ScopedFastNativeObjectAccess soa(env);
- mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
- // JNI must use non transactional mode (SetField8 is non-transactional).
- obj->SetFieldBoolean<false>(MemberOffset(offset), newValue);
+ ScopedFastNativeObjectAccess soa(env);
+ ObjPtr<mirror::Object> obj = soa.Decode<mirror::Object>(javaObj);
+ // JNI must use non transactional mode (SetField8 is non-transactional).
+ obj->SetFieldBoolean<false>(MemberOffset(offset), newValue);
}
static jbyte Unsafe_getByte(JNIEnv* env, jobject, jobject javaObj, jlong offset) {
- ScopedFastNativeObjectAccess soa(env);
- mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
- return obj->GetFieldByte(MemberOffset(offset));
+ ScopedFastNativeObjectAccess soa(env);
+ ObjPtr<mirror::Object> obj = soa.Decode<mirror::Object>(javaObj);
+ return obj->GetFieldByte(MemberOffset(offset));
}
static void Unsafe_putByte(JNIEnv* env, jobject, jobject javaObj, jlong offset, jbyte newValue) {
- ScopedFastNativeObjectAccess soa(env);
- mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
- // JNI must use non transactional mode.
- obj->SetFieldByte<false>(MemberOffset(offset), newValue);
+ ScopedFastNativeObjectAccess soa(env);
+ ObjPtr<mirror::Object> obj = soa.Decode<mirror::Object>(javaObj);
+ // JNI must use non transactional mode.
+ obj->SetFieldByte<false>(MemberOffset(offset), newValue);
}
static jchar Unsafe_getChar(JNIEnv* env, jobject, jobject javaObj, jlong offset) {
- ScopedFastNativeObjectAccess soa(env);
- mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
- return obj->GetFieldChar(MemberOffset(offset));
+ ScopedFastNativeObjectAccess soa(env);
+ ObjPtr<mirror::Object> obj = soa.Decode<mirror::Object>(javaObj);
+ return obj->GetFieldChar(MemberOffset(offset));
}
static void Unsafe_putChar(JNIEnv* env, jobject, jobject javaObj, jlong offset, jchar newValue) {
- ScopedFastNativeObjectAccess soa(env);
- mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
- // JNI must use non transactional mode.
- obj->SetFieldChar<false>(MemberOffset(offset), newValue);
+ ScopedFastNativeObjectAccess soa(env);
+ ObjPtr<mirror::Object> obj = soa.Decode<mirror::Object>(javaObj);
+ // JNI must use non transactional mode.
+ obj->SetFieldChar<false>(MemberOffset(offset), newValue);
}
static jshort Unsafe_getShort(JNIEnv* env, jobject, jobject javaObj, jlong offset) {
- ScopedFastNativeObjectAccess soa(env);
- mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
- return obj->GetFieldShort(MemberOffset(offset));
+ ScopedFastNativeObjectAccess soa(env);
+ ObjPtr<mirror::Object> obj = soa.Decode<mirror::Object>(javaObj);
+ return obj->GetFieldShort(MemberOffset(offset));
}
static void Unsafe_putShort(JNIEnv* env, jobject, jobject javaObj, jlong offset, jshort newValue) {
- ScopedFastNativeObjectAccess soa(env);
- mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
- // JNI must use non transactional mode.
- obj->SetFieldShort<false>(MemberOffset(offset), newValue);
+ ScopedFastNativeObjectAccess soa(env);
+ ObjPtr<mirror::Object> obj = soa.Decode<mirror::Object>(javaObj);
+ // JNI must use non transactional mode.
+ obj->SetFieldShort<false>(MemberOffset(offset), newValue);
}
static jfloat Unsafe_getFloat(JNIEnv* env, jobject, jobject javaObj, jlong offset) {
ScopedFastNativeObjectAccess soa(env);
- mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
+ ObjPtr<mirror::Object> obj = soa.Decode<mirror::Object>(javaObj);
union {int32_t val; jfloat converted;} conv;
conv.val = obj->GetField32(MemberOffset(offset));
return conv.converted;
@@ -450,7 +453,7 @@
static void Unsafe_putFloat(JNIEnv* env, jobject, jobject javaObj, jlong offset, jfloat newValue) {
ScopedFastNativeObjectAccess soa(env);
- mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
+ ObjPtr<mirror::Object> obj = soa.Decode<mirror::Object>(javaObj);
union {int32_t converted; jfloat val;} conv;
conv.val = newValue;
// JNI must use non transactional mode.
@@ -459,7 +462,7 @@
static jdouble Unsafe_getDouble(JNIEnv* env, jobject, jobject javaObj, jlong offset) {
ScopedFastNativeObjectAccess soa(env);
- mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
+ ObjPtr<mirror::Object> obj = soa.Decode<mirror::Object>(javaObj);
union {int64_t val; jdouble converted;} conv;
conv.val = obj->GetField64(MemberOffset(offset));
return conv.converted;
@@ -467,7 +470,7 @@
static void Unsafe_putDouble(JNIEnv* env, jobject, jobject javaObj, jlong offset, jdouble newValue) {
ScopedFastNativeObjectAccess soa(env);
- mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
+ ObjPtr<mirror::Object> obj = soa.Decode<mirror::Object>(javaObj);
union {int64_t converted; jdouble val;} conv;
conv.val = newValue;
// JNI must use non transactional mode.
diff --git a/runtime/native_bridge_art_interface.cc b/runtime/native_bridge_art_interface.cc
index 155c008..059dc5a 100644
--- a/runtime/native_bridge_art_interface.cc
+++ b/runtime/native_bridge_art_interface.cc
@@ -26,7 +26,7 @@
#include "base/macros.h"
#include "dex_file-inl.h"
#include "mirror/class-inl.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
#include "sigchain.h"
namespace art {
@@ -43,7 +43,7 @@
}
ScopedObjectAccess soa(env);
- mirror::Class* c = soa.Decode<mirror::Class*>(clazz);
+ ObjPtr<mirror::Class> c = soa.Decode<mirror::Class>(clazz);
uint32_t native_method_count = 0;
for (auto& m : c->GetMethods(kRuntimePointerSize)) {
@@ -58,7 +58,7 @@
return 0;
}
ScopedObjectAccess soa(env);
- mirror::Class* c = soa.Decode<mirror::Class*>(clazz);
+ ObjPtr<mirror::Class> c = soa.Decode<mirror::Class>(clazz);
uint32_t count = 0;
for (auto& m : c->GetMethods(kRuntimePointerSize)) {
diff --git a/runtime/oat.h b/runtime/oat.h
index 12a8298..4d8687c 100644
--- a/runtime/oat.h
+++ b/runtime/oat.h
@@ -32,7 +32,7 @@
class PACKED(4) OatHeader {
public:
static constexpr uint8_t kOatMagic[] = { 'o', 'a', 't', '\n' };
- static constexpr uint8_t kOatVersion[] = { '0', '8', '7', '\0' };
+ static constexpr uint8_t kOatVersion[] = { '0', '8', '9', '\0' };
static constexpr const char* kImageLocationKey = "image-location";
static constexpr const char* kDex2OatCmdLineKey = "dex2oat-cmdline";
diff --git a/runtime/oat_file_assistant.cc b/runtime/oat_file_assistant.cc
index 415f991..ff00451 100644
--- a/runtime/oat_file_assistant.cc
+++ b/runtime/oat_file_assistant.cc
@@ -27,7 +27,7 @@
#include "oat.h"
#include "os.h"
#include "runtime.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
#include "utils.h"
namespace art {
diff --git a/runtime/oat_file_assistant_test.cc b/runtime/oat_file_assistant_test.cc
index 6ec5e55..d18e946 100644
--- a/runtime/oat_file_assistant_test.cc
+++ b/runtime/oat_file_assistant_test.cc
@@ -33,7 +33,7 @@
#include "oat_file_assistant.h"
#include "oat_file_manager.h"
#include "os.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
#include "thread-inl.h"
#include "utils.h"
diff --git a/runtime/oat_file_manager.cc b/runtime/oat_file_manager.cc
index 6d4b2f6..acad2a9 100644
--- a/runtime/oat_file_manager.cc
+++ b/runtime/oat_file_manager.cc
@@ -30,7 +30,7 @@
#include "handle_scope-inl.h"
#include "mirror/class_loader.h"
#include "oat_file_assistant.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
#include "thread-inl.h"
#include "thread_list.h"
@@ -294,8 +294,8 @@
}
// Unsupported class-loader?
- if (class_loader->GetClass() !=
- soa.Decode<mirror::Class*>(WellKnownClasses::dalvik_system_PathClassLoader)) {
+ if (soa.Decode<mirror::Class>(WellKnownClasses::dalvik_system_PathClassLoader) !=
+ class_loader->GetClass()) {
VLOG(class_linker) << "Unsupported class-loader " << PrettyClass(class_loader->GetClass());
return false;
}
@@ -338,10 +338,10 @@
ArtField* const cookie_field = soa.DecodeField(WellKnownClasses::dalvik_system_DexFile_cookie);
ArtField* const dex_file_field =
soa.DecodeField(WellKnownClasses::dalvik_system_DexPathList__Element_dexFile);
- const mirror::Class* const element_class = soa.Decode<mirror::Class*>(
+ ObjPtr<mirror::Class> const element_class = soa.Decode<mirror::Class>(
WellKnownClasses::dalvik_system_DexPathList__Element);
- const mirror::Class* const dexfile_class = soa.Decode<mirror::Class*>(
- WellKnownClasses::dalvik_system_DexFile);
+ ObjPtr<mirror::Class> const dexfile_class = soa.Decode<mirror::Class>(
+ WellKnownClasses::dalvik_system_DexFile);
// Collect all the dex files.
auto GetDexFilesFn = [&] (const DexFile* cp_dex_file)
@@ -361,9 +361,9 @@
// We support this being dalvik.system.DexPathList$Element and dalvik.system.DexFile.
mirror::Object* dex_file;
- if (element->GetClass() == element_class) {
+ if (element_class == element->GetClass()) {
dex_file = dex_file_field->GetObject(element);
- } else if (element->GetClass() == dexfile_class) {
+ } else if (dexfile_class == element->GetClass()) {
dex_file = element;
} else {
LOG(WARNING) << "Unsupported element in dex_elements: " << PrettyClass(element->GetClass());
@@ -442,9 +442,9 @@
ScopedObjectAccess soa(Thread::Current());
StackHandleScope<2> hs(Thread::Current());
Handle<mirror::ClassLoader> h_class_loader =
- hs.NewHandle(soa.Decode<mirror::ClassLoader*>(class_loader));
+ hs.NewHandle(soa.Decode<mirror::ClassLoader>(class_loader));
Handle<mirror::ObjectArray<mirror::Object>> h_dex_elements =
- hs.NewHandle(soa.Decode<mirror::ObjectArray<mirror::Object>*>(dex_elements));
+ hs.NewHandle(soa.Decode<mirror::ObjectArray<mirror::Object>>(dex_elements));
if (h_class_loader.Get() != nullptr &&
GetDexFilesFromClassLoader(soa, h_class_loader.Get(), &queue)) {
class_loader_ok = true;
@@ -638,7 +638,7 @@
ScopedObjectAccess soa(self);
StackHandleScope<1> hs(self);
Handle<mirror::ClassLoader> h_loader(
- hs.NewHandle(soa.Decode<mirror::ClassLoader*>(class_loader)));
+ hs.NewHandle(soa.Decode<mirror::ClassLoader>(class_loader)));
// Can not load app image without class loader.
if (h_loader.Get() != nullptr) {
std::string temp_error_msg;
diff --git a/runtime/oat_file_test.cc b/runtime/oat_file_test.cc
index a88553c..b416b9d 100644
--- a/runtime/oat_file_test.cc
+++ b/runtime/oat_file_test.cc
@@ -21,7 +21,7 @@
#include <gtest/gtest.h>
#include "common_runtime_test.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
namespace art {
diff --git a/runtime/oat_quick_method_header.cc b/runtime/oat_quick_method_header.cc
index 0ab2bfe..a68d9f8 100644
--- a/runtime/oat_quick_method_header.cc
+++ b/runtime/oat_quick_method_header.cc
@@ -17,7 +17,7 @@
#include "oat_quick_method_header.h"
#include "art_method.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
#include "thread.h"
namespace art {
diff --git a/runtime/obj_ptr-inl.h b/runtime/obj_ptr-inl.h
new file mode 100644
index 0000000..1c698b5
--- /dev/null
+++ b/runtime/obj_ptr-inl.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_RUNTIME_OBJ_PTR_INL_H_
+#define ART_RUNTIME_OBJ_PTR_INL_H_
+
+#include "obj_ptr.h"
+#include "thread-inl.h"
+
+namespace art {
+
+template<class MirrorType, bool kPoison>
+inline bool ObjPtr<MirrorType, kPoison>::IsValid() const {
+ if (!kPoison || IsNull()) {
+ return true;
+ }
+ return GetCookie() == TrimCookie(Thread::Current()->GetPoisonObjectCookie());
+}
+
+template<class MirrorType, bool kPoison>
+inline void ObjPtr<MirrorType, kPoison>::AssertValid() const {
+ if (kPoison) {
+ CHECK(IsValid()) << "Stale object pointer " << DecodeUnchecked() << " , expected cookie "
+ << TrimCookie(Thread::Current()->GetPoisonObjectCookie()) << " but got " << GetCookie();
+ }
+}
+
+template<class MirrorType, bool kPoison>
+inline uintptr_t ObjPtr<MirrorType, kPoison>::Encode(MirrorType* ptr) {
+ uintptr_t ref = reinterpret_cast<uintptr_t>(ptr);
+ DCHECK_ALIGNED(ref, kObjectAlignment);
+ if (kPoison && ref != 0) {
+ DCHECK_LE(ref, 0xFFFFFFFFU);
+ ref >>= kObjectAlignmentShift;
+ // Put cookie in high bits.
+ Thread* self = Thread::Current();
+ DCHECK(self != nullptr);
+ ref |= self->GetPoisonObjectCookie() << kCookieShift;
+ }
+ return ref;
+}
+
+template<class MirrorType, bool kPoison>
+inline std::ostream& operator<<(std::ostream& os, ObjPtr<MirrorType, kPoison> ptr) {
+ // May be used for dumping bad pointers, do not use the checked version.
+ return os << ptr.DecodeUnchecked();
+}
+
+} // namespace art
+
+#endif // ART_RUNTIME_OBJ_PTR_INL_H_
diff --git a/runtime/mirror/obj_ptr.h b/runtime/obj_ptr.h
similarity index 72%
rename from runtime/mirror/obj_ptr.h
rename to runtime/obj_ptr.h
index 10378e8..d5ac33d 100644
--- a/runtime/mirror/obj_ptr.h
+++ b/runtime/obj_ptr.h
@@ -14,23 +14,20 @@
* limitations under the License.
*/
-#ifndef ART_RUNTIME_MIRROR_OBJ_PTR_H_
-#define ART_RUNTIME_MIRROR_OBJ_PTR_H_
+#ifndef ART_RUNTIME_OBJ_PTR_H_
+#define ART_RUNTIME_OBJ_PTR_H_
+
+#include <ostream>
#include "base/mutex.h" // For Locks::mutator_lock_.
#include "globals.h"
#include "mirror/object_reference.h"
-#include "utils.h"
namespace art {
-namespace mirror {
-
-class Object;
// Value type representing a pointer to a mirror::Object of type MirrorType
// Pass kPoison as a template boolean for testing in non-debug builds.
-// Note that the functions are not 100% thread safe and may have spurious positive check passes in
-// these cases.
+// Since the cookie is thread based, it is not safe to share an ObjPtr between threads.
template<class MirrorType, bool kPoison = kIsDebugBuild>
class ObjPtr {
static constexpr size_t kCookieShift =
@@ -44,14 +41,19 @@
public:
ALWAYS_INLINE ObjPtr() REQUIRES_SHARED(Locks::mutator_lock_) : reference_(0u) {}
- ALWAYS_INLINE explicit ObjPtr(MirrorType* ptr) REQUIRES_SHARED(Locks::mutator_lock_)
- : reference_(Encode(ptr)) {}
+ ALWAYS_INLINE ObjPtr(std::nullptr_t) REQUIRES_SHARED(Locks::mutator_lock_) : reference_(0u) {}
- ALWAYS_INLINE explicit ObjPtr(const ObjPtr& other) REQUIRES_SHARED(Locks::mutator_lock_)
- = default;
+ template <typename Type>
+ ALWAYS_INLINE ObjPtr(Type* ptr) REQUIRES_SHARED(Locks::mutator_lock_)
+ : reference_(Encode(static_cast<MirrorType*>(ptr))) {}
+ template <typename Type>
+ ALWAYS_INLINE ObjPtr(const ObjPtr<Type>& other) REQUIRES_SHARED(Locks::mutator_lock_)
+ : reference_(Encode(static_cast<MirrorType*>(other.Decode()))) {}
+
+ template <typename Type>
ALWAYS_INLINE ObjPtr& operator=(const ObjPtr& other) {
- reference_ = other.reference_;
+ reference_ = Encode(static_cast<MirrorType*>(other.Decode()));
return *this;
}
@@ -65,10 +67,6 @@
}
ALWAYS_INLINE MirrorType* operator->() const REQUIRES_SHARED(Locks::mutator_lock_) {
- return Get();
- }
-
- ALWAYS_INLINE MirrorType* Get() const REQUIRES_SHARED(Locks::mutator_lock_) {
return Decode();
}
@@ -76,19 +74,15 @@
return reference_ == 0;
}
- ALWAYS_INLINE bool IsValid() const REQUIRES_SHARED(Locks::mutator_lock_) {
- if (!kPoison || IsNull()) {
- return true;
- }
- return GetCookie() == TrimCookie(Thread::Current()->GetPoisonObjectCookie());
+ // Decode makes sure that the object pointer is valid.
+ ALWAYS_INLINE MirrorType* Decode() const REQUIRES_SHARED(Locks::mutator_lock_) {
+ AssertValid();
+ return DecodeUnchecked();
}
- ALWAYS_INLINE void AssertValid() const REQUIRES_SHARED(Locks::mutator_lock_) {
- if (kPoison) {
- CHECK(IsValid()) << "Stale object pointer, expected cookie "
- << TrimCookie(Thread::Current()->GetPoisonObjectCookie()) << " but got " << GetCookie();
- }
- }
+ ALWAYS_INLINE bool IsValid() const REQUIRES_SHARED(Locks::mutator_lock_);
+
+ ALWAYS_INLINE void AssertValid() const REQUIRES_SHARED(Locks::mutator_lock_);
ALWAYS_INLINE bool operator==(const ObjPtr& ptr) const REQUIRES_SHARED(Locks::mutator_lock_) {
return Decode() == ptr.Decode();
@@ -114,6 +108,16 @@
return !IsNull();
}
+ // Decode unchecked does not check that object pointer is valid. Do not use if you can avoid it.
+ ALWAYS_INLINE MirrorType* DecodeUnchecked() const REQUIRES_SHARED(Locks::mutator_lock_) {
+ if (kPoison) {
+ return reinterpret_cast<MirrorType*>(
+ static_cast<uintptr_t>(static_cast<uint32_t>(reference_ << kObjectAlignmentShift)));
+ } else {
+ return reinterpret_cast<MirrorType*>(reference_);
+ }
+ }
+
private:
// Trim off high bits of thread local cookie.
ALWAYS_INLINE static uintptr_t TrimCookie(uintptr_t cookie) {
@@ -124,36 +128,20 @@
return reference_ >> kCookieShift;
}
- ALWAYS_INLINE static uintptr_t Encode(MirrorType* ptr) REQUIRES_SHARED(Locks::mutator_lock_) {
- uintptr_t ref = reinterpret_cast<uintptr_t>(ptr);
- if (kPoison && ref != 0) {
- DCHECK_LE(ref, 0xFFFFFFFFU);
- ref >>= kObjectAlignmentShift;
- // Put cookie in high bits.
- Thread* self = Thread::Current();
- DCHECK(self != nullptr);
- ref |= self->GetPoisonObjectCookie() << kCookieShift;
- }
- return ref;
- }
-
- // Decode makes sure that the object pointer is valid.
- ALWAYS_INLINE MirrorType* Decode() const REQUIRES_SHARED(Locks::mutator_lock_) {
- AssertValid();
- if (kPoison) {
- return reinterpret_cast<MirrorType*>(
- static_cast<uintptr_t>(static_cast<uint32_t>(reference_ << kObjectAlignmentShift)));
- } else {
- return reinterpret_cast<MirrorType*>(reference_);
- }
- }
-
+ ALWAYS_INLINE static uintptr_t Encode(MirrorType* ptr) REQUIRES_SHARED(Locks::mutator_lock_);
// The encoded reference and cookie.
uintptr_t reference_;
};
+template<class MirrorType, bool kPoison = kIsDebugBuild>
+static inline ObjPtr<MirrorType, kPoison> MakeObjPtr(MirrorType* ptr) {
+ return ObjPtr<MirrorType, kPoison>(ptr);
+}
-} // namespace mirror
+template<class MirrorType, bool kPoison>
+ALWAYS_INLINE std::ostream& operator<<(std::ostream& os, ObjPtr<MirrorType, kPoison> ptr)
+ REQUIRES_SHARED(Locks::mutator_lock_);
+
} // namespace art
-#endif // ART_RUNTIME_MIRROR_OBJ_PTR_H_
+#endif // ART_RUNTIME_OBJ_PTR_H_
diff --git a/runtime/openjdkjvm/OpenjdkJvm.cc b/runtime/openjdkjvm/OpenjdkJvm.cc
index 4a62ecd..d46d78c 100644
--- a/runtime/openjdkjvm/OpenjdkJvm.cc
+++ b/runtime/openjdkjvm/OpenjdkJvm.cc
@@ -43,7 +43,7 @@
#include "thread_list.h"
#include "runtime.h"
#include "handle_scope-inl.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
#include "ScopedUtfChars.h"
#include "mirror/class_loader.h"
#include "verify_object-inl.h"
@@ -52,7 +52,7 @@
#include "../../libcore/ojluni/src/main/native/jvm.h" // TODO(narayan): fix it
#include "jni_internal.h"
#include "mirror/string-inl.h"
-#include "native/scoped_fast_native_object_access.h"
+#include "native/scoped_fast_native_object_access-inl.h"
#include "ScopedLocalRef.h"
#include <sys/time.h>
#include <sys/socket.h>
@@ -286,9 +286,8 @@
JNIEXPORT jstring JVM_InternString(JNIEnv* env, jstring jstr) {
art::ScopedFastNativeObjectAccess soa(env);
- art::mirror::String* s = soa.Decode<art::mirror::String*>(jstr);
- art::mirror::String* result = s->Intern();
- return soa.AddLocalReference<jstring>(result);
+ art::ObjPtr<art::mirror::String> s = soa.Decode<art::mirror::String>(jstr);
+ return soa.AddLocalReference<jstring>(s->Intern());
}
JNIEXPORT jlong JVM_FreeMemory(void) {
@@ -364,8 +363,8 @@
JNIEXPORT void JVM_Sleep(JNIEnv* env, jclass threadClass ATTRIBUTE_UNUSED,
jobject java_lock, jlong millis) {
art::ScopedFastNativeObjectAccess soa(env);
- art::mirror::Object* lock = soa.Decode<art::mirror::Object*>(java_lock);
- art::Monitor::Wait(art::Thread::Current(), lock, millis, 0, true, art::kSleeping);
+ art::ObjPtr<art::mirror::Object> lock = soa.Decode<art::mirror::Object>(java_lock);
+ art::Monitor::Wait(art::Thread::Current(), lock.Decode(), millis, 0, true, art::kSleeping);
}
JNIEXPORT jobject JVM_CurrentThread(JNIEnv* env, jclass unused ATTRIBUTE_UNUSED) {
@@ -395,19 +394,19 @@
JNIEXPORT jboolean JVM_HoldsLock(JNIEnv* env, jclass unused ATTRIBUTE_UNUSED, jobject jobj) {
art::ScopedObjectAccess soa(env);
- art::mirror::Object* object = soa.Decode<art::mirror::Object*>(jobj);
- if (object == NULL) {
+ art::ObjPtr<art::mirror::Object> object = soa.Decode<art::mirror::Object>(jobj);
+ if (object == nullptr) {
art::ThrowNullPointerException("object == null");
return JNI_FALSE;
}
- return soa.Self()->HoldsLock(object);
+ return soa.Self()->HoldsLock(object.Decode());
}
JNIEXPORT void JVM_SetNativeThreadName(JNIEnv* env, jobject jthread, jstring java_name) {
ScopedUtfChars name(env, java_name);
{
art::ScopedObjectAccess soa(env);
- if (soa.Decode<art::mirror::Object*>(jthread) == soa.Self()->GetPeer()) {
+ if (soa.Decode<art::mirror::Object>(jthread) == soa.Self()->GetPeer()) {
soa.Self()->SetThreadName(name.c_str());
return;
}
diff --git a/runtime/openjdkjvmti/transform.cc b/runtime/openjdkjvmti/transform.cc
index b5622b5..ac348e7 100644
--- a/runtime/openjdkjvmti/transform.cc
+++ b/runtime/openjdkjvmti/transform.cc
@@ -43,7 +43,7 @@
#include "mirror/class-inl.h"
#include "mirror/class_loader-inl.h"
#include "mirror/string-inl.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
#include "thread_list.h"
#include "transform.h"
#include "utf.h"
@@ -259,7 +259,7 @@
JNIEnv* jni_env = *jni_env_ptr;
art::ScopedObjectAccess soa(jni_env);
art::StackHandleScope<3> hs(art::Thread::Current());
- art::Handle<art::mirror::Class> hs_klass(hs.NewHandle(soa.Decode<art::mirror::Class*>(klass)));
+ art::Handle<art::mirror::Class> hs_klass(hs.NewHandle(soa.Decode<art::mirror::Class>(klass)));
*loader = soa.AddLocalReference<jobject>(hs_klass->GetClassLoader());
*name = art::mirror::Class::ComputeName(hs_klass)->ToModifiedUtf8();
// TODO is this always null?
diff --git a/runtime/proxy_test.cc b/runtime/proxy_test.cc
index e3f92c7..43b0b3d 100644
--- a/runtime/proxy_test.cc
+++ b/runtime/proxy_test.cc
@@ -23,7 +23,7 @@
#include "common_compiler_test.h"
#include "mirror/field-inl.h"
#include "mirror/method.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
namespace art {
@@ -108,7 +108,7 @@
jobject jclass_loader = LoadDex("Interfaces");
StackHandleScope<4> hs(soa.Self());
Handle<mirror::ClassLoader> class_loader(
- hs.NewHandle(soa.Decode<mirror::ClassLoader*>(jclass_loader)));
+ hs.NewHandle(soa.Decode<mirror::ClassLoader>(jclass_loader)));
Handle<mirror::Class> I(hs.NewHandle(
class_linker_->FindClass(soa.Self(), "LInterfaces$I;", class_loader)));
@@ -142,7 +142,7 @@
jobject jclass_loader = LoadDex("Interfaces");
StackHandleScope<9> hs(soa.Self());
Handle<mirror::ClassLoader> class_loader(
- hs.NewHandle(soa.Decode<mirror::ClassLoader*>(jclass_loader)));
+ hs.NewHandle(soa.Decode<mirror::ClassLoader>(jclass_loader)));
Handle<mirror::Class> I(hs.NewHandle(
class_linker_->FindClass(soa.Self(), "LInterfaces$I;", class_loader)));
@@ -200,7 +200,7 @@
jobject jclass_loader = LoadDex("Interfaces");
StackHandleScope<7> hs(soa.Self());
Handle<mirror::ClassLoader> class_loader(
- hs.NewHandle(soa.Decode<mirror::ClassLoader*>(jclass_loader)));
+ hs.NewHandle(soa.Decode<mirror::ClassLoader>(jclass_loader)));
Handle<mirror::Class> proxyClass0;
Handle<mirror::Class> proxyClass1;
diff --git a/runtime/reference_table.cc b/runtime/reference_table.cc
index f04d41d..0be79ef 100644
--- a/runtime/reference_table.cc
+++ b/runtime/reference_table.cc
@@ -192,6 +192,13 @@
} else {
StringAppendF(&extras, " \"%.16s... (%d chars)", utf8.c_str(), s->GetLength());
}
+ } else if (ref->IsReferenceInstance()) {
+ mirror::Object* referent = ref->AsReference()->GetReferent();
+ if (referent == nullptr) {
+ extras = " (referent is null)";
+ } else {
+ extras = StringPrintf(" (referent is a %s)", PrettyTypeOf(referent).c_str());
+ }
}
os << StringPrintf(" %5d: ", idx) << ref << " " << className << extras << "\n";
}
diff --git a/runtime/reference_table_test.cc b/runtime/reference_table_test.cc
index fae8e72..489db9a 100644
--- a/runtime/reference_table_test.cc
+++ b/runtime/reference_table_test.cc
@@ -16,18 +16,55 @@
#include "reference_table.h"
+#include "class_linker.h"
#include "common_runtime_test.h"
+#include "handle_scope-inl.h"
#include "mirror/array-inl.h"
#include "mirror/class-inl.h"
+#include "mirror/class_loader.h"
#include "mirror/string.h"
#include "primitive.h"
-#include "scoped_thread_state_change.h"
+#include "runtime.h"
+#include "scoped_thread_state_change-inl.h"
#include "thread-inl.h"
namespace art {
class ReferenceTableTest : public CommonRuntimeTest {};
+static mirror::Object* CreateWeakReference(mirror::Object* referent)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ Thread* self = Thread::Current();
+ ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+
+ StackHandleScope<3> scope(self);
+ Handle<mirror::Object> h_referent(scope.NewHandle<mirror::Object>(referent));
+
+ Handle<mirror::Class> h_ref_class(scope.NewHandle<mirror::Class>(
+ class_linker->FindClass(self,
+ "Ljava/lang/ref/WeakReference;",
+ ScopedNullHandle<mirror::ClassLoader>())));
+ CHECK(h_ref_class.Get() != nullptr);
+ CHECK(class_linker->EnsureInitialized(self, h_ref_class, true, true));
+
+ Handle<mirror::Object> h_ref_instance(scope.NewHandle<mirror::Object>(
+ h_ref_class->AllocObject(self)));
+ CHECK(h_ref_instance.Get() != nullptr);
+
+ ArtMethod* constructor = h_ref_class->FindDeclaredDirectMethod(
+ "<init>", "(Ljava/lang/Object;)V", class_linker->GetImagePointerSize());
+ CHECK(constructor != nullptr);
+
+ uint32_t args[2];
+ args[0] = PointerToLowMemUInt32(h_ref_instance.Get());
+ args[1] = PointerToLowMemUInt32(h_referent.Get());
+ JValue result;
+ constructor->Invoke(self, args, sizeof(uint32_t), &result, constructor->GetShorty());
+ CHECK(!self->IsExceptionPending());
+
+ return h_ref_instance.Get();
+}
+
TEST_F(ReferenceTableTest, Basics) {
ScopedObjectAccess soa(Thread::Current());
mirror::Object* o1 = mirror::String::AllocFromModifiedUtf8(soa.Self(), "hello");
@@ -104,6 +141,29 @@
std::string::npos) << oss.str();
}
}
+
+ // Add a reference and check that the type of the referent is dumped.
+ {
+ mirror::Object* empty_reference = CreateWeakReference(nullptr);
+ ASSERT_TRUE(empty_reference->IsReferenceInstance());
+ rt.Add(empty_reference);
+ std::ostringstream oss;
+ rt.Dump(oss);
+ EXPECT_NE(oss.str().find("java.lang.ref.WeakReference (referent is null)"), std::string::npos)
+ << oss.str();
+ }
+
+ {
+ mirror::Object* string_referent = mirror::String::AllocFromModifiedUtf8(Thread::Current(), "A");
+ mirror::Object* non_empty_reference = CreateWeakReference(string_referent);
+ ASSERT_TRUE(non_empty_reference->IsReferenceInstance());
+ rt.Add(non_empty_reference);
+ std::ostringstream oss;
+ rt.Dump(oss);
+ EXPECT_NE(oss.str().find("java.lang.ref.WeakReference (referent is a java.lang.String)"),
+ std::string::npos)
+ << oss.str();
+ }
}
} // namespace art
diff --git a/runtime/reflection-inl.h b/runtime/reflection-inl.h
index f54d4ca..d7db8a4 100644
--- a/runtime/reflection-inl.h
+++ b/runtime/reflection-inl.h
@@ -23,14 +23,17 @@
#include "common_throws.h"
#include "jvalue.h"
#include "mirror/object-inl.h"
+#include "obj_ptr-inl.h"
#include "primitive.h"
#include "utils.h"
namespace art {
inline bool ConvertPrimitiveValue(bool unbox_for_result,
- Primitive::Type srcType, Primitive::Type dstType,
- const JValue& src, JValue* dst) {
+ Primitive::Type srcType,
+ Primitive::Type dstType,
+ const JValue& src,
+ JValue* dst) {
DCHECK(srcType != Primitive::kPrimNot && dstType != Primitive::kPrimNot);
if (LIKELY(srcType == dstType)) {
dst->SetJ(src.GetJ());
@@ -100,11 +103,11 @@
return false;
}
-inline bool VerifyObjectIsClass(mirror::Object* o, mirror::Class* c) {
+inline bool VerifyObjectIsClass(ObjPtr<mirror::Object> o, ObjPtr<mirror::Class> c) {
if (UNLIKELY(o == nullptr)) {
ThrowNullPointerException("null receiver");
return false;
- } else if (UNLIKELY(!o->InstanceOf(c))) {
+ } else if (UNLIKELY(!o->InstanceOf(c.Decode()))) {
InvalidReceiverError(o, c);
return false;
}
diff --git a/runtime/reflection.cc b/runtime/reflection.cc
index 30b10d8..b663b4c 100644
--- a/runtime/reflection.cc
+++ b/runtime/reflection.cc
@@ -28,7 +28,7 @@
#include "mirror/executable.h"
#include "mirror/object_array-inl.h"
#include "nth_caller_visitor.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
#include "stack_reference.h"
#include "well_known_classes.h"
@@ -72,8 +72,8 @@
num_bytes_ += 4;
}
- void Append(mirror::Object* obj) REQUIRES_SHARED(Locks::mutator_lock_) {
- Append(StackReference<mirror::Object>::FromMirrorPtr(obj).AsVRegValue());
+ void Append(ObjPtr<mirror::Object> obj) REQUIRES_SHARED(Locks::mutator_lock_) {
+ Append(StackReference<mirror::Object>::FromMirrorPtr(obj.Decode()).AsVRegValue());
}
void AppendWide(uint64_t value) {
@@ -95,7 +95,8 @@
}
void BuildArgArrayFromVarArgs(const ScopedObjectAccessAlreadyRunnable& soa,
- mirror::Object* receiver, va_list ap)
+ ObjPtr<mirror::Object> receiver,
+ va_list ap)
REQUIRES_SHARED(Locks::mutator_lock_) {
// Set receiver if non-null (method is not static)
if (receiver != nullptr) {
@@ -114,7 +115,7 @@
AppendFloat(va_arg(ap, jdouble));
break;
case 'L':
- Append(soa.Decode<mirror::Object*>(va_arg(ap, jobject)));
+ Append(soa.Decode<mirror::Object>(va_arg(ap, jobject)));
break;
case 'D':
AppendDouble(va_arg(ap, jdouble));
@@ -131,7 +132,7 @@
}
void BuildArgArrayFromJValues(const ScopedObjectAccessAlreadyRunnable& soa,
- mirror::Object* receiver, jvalue* args)
+ ObjPtr<mirror::Object> receiver, jvalue* args)
REQUIRES_SHARED(Locks::mutator_lock_) {
// Set receiver if non-null (method is not static)
if (receiver != nullptr) {
@@ -156,7 +157,7 @@
Append(args[args_offset].i);
break;
case 'L':
- Append(soa.Decode<mirror::Object*>(args[args_offset].l));
+ Append(soa.Decode<mirror::Object>(args[args_offset].l));
break;
case 'D':
case 'J':
@@ -212,8 +213,9 @@
PrettyDescriptor(found_descriptor).c_str()).c_str());
}
- bool BuildArgArrayFromObjectArray(mirror::Object* receiver,
- mirror::ObjectArray<mirror::Object>* args, ArtMethod* m)
+ bool BuildArgArrayFromObjectArray(ObjPtr<mirror::Object> receiver,
+ ObjPtr<mirror::ObjectArray<mirror::Object>> args,
+ ArtMethod* m)
REQUIRES_SHARED(Locks::mutator_lock_) {
const DexFile::TypeList* classes = m->GetParameterTypeList();
// Set receiver if non-null (method is not static)
@@ -221,13 +223,13 @@
Append(receiver);
}
for (size_t i = 1, args_offset = 0; i < shorty_len_; ++i, ++args_offset) {
- mirror::Object* arg = args->Get(args_offset);
+ ObjPtr<mirror::Object> arg(args->Get(args_offset));
if (((shorty_[i] == 'L') && (arg != nullptr)) || ((arg == nullptr && shorty_[i] != 'L'))) {
PointerSize pointer_size = Runtime::Current()->GetClassLinker()->GetImagePointerSize();
- mirror::Class* dst_class =
+ ObjPtr<mirror::Class> dst_class(
m->GetClassFromTypeIndex(classes->GetTypeItem(args_offset).type_idx_,
true /* resolve */,
- pointer_size);
+ pointer_size));
if (UNLIKELY(arg == nullptr || !arg->InstanceOf(dst_class))) {
ThrowIllegalArgumentException(
StringPrintf("method %s argument %zd has type %s, got %s",
@@ -240,15 +242,15 @@
}
#define DO_FIRST_ARG(match_descriptor, get_fn, append) { \
- if (LIKELY(arg != nullptr && arg->GetClass<>()->DescriptorEquals(match_descriptor))) { \
+ if (LIKELY(arg != nullptr && arg->GetClass()->DescriptorEquals(match_descriptor))) { \
ArtField* primitive_field = arg->GetClass()->GetInstanceField(0); \
- append(primitive_field-> get_fn(arg));
+ append(primitive_field-> get_fn(arg.Decode()));
#define DO_ARG(match_descriptor, get_fn, append) \
} else if (LIKELY(arg != nullptr && \
arg->GetClass<>()->DescriptorEquals(match_descriptor))) { \
ArtField* primitive_field = arg->GetClass()->GetInstanceField(0); \
- append(primitive_field-> get_fn(arg));
+ append(primitive_field-> get_fn(arg.Decode()));
#define DO_FAIL(expected) \
} else { \
@@ -362,9 +364,9 @@
PointerSize pointer_size = Runtime::Current()->GetClassLinker()->GetImagePointerSize();
for (uint32_t i = 0; i < num_params; i++) {
uint16_t type_idx = params->GetTypeItem(i).type_idx_;
- mirror::Class* param_type = m->GetClassFromTypeIndex(type_idx,
- true /* resolve*/,
- pointer_size);
+ ObjPtr<mirror::Class> param_type(m->GetClassFromTypeIndex(type_idx,
+ true /* resolve*/,
+ pointer_size));
if (param_type == nullptr) {
CHECK(self->IsExceptionPending());
LOG(ERROR) << "Internal error: unresolvable type for argument type in JNI invoke: "
@@ -376,7 +378,7 @@
// TODO: There is a compaction bug here since GetClassFromTypeIdx can cause thread suspension,
// this is a hard to fix problem since the args can contain Object*, we need to save and
// restore them by using a visitor similar to the ones used in the trampoline entrypoints.
- mirror::Object* argument =
+ ObjPtr<mirror::Object> argument =
(reinterpret_cast<StackReference<mirror::Object>*>(&args[i + offset]))->AsMirrorPtr();
if (argument != nullptr && !argument->InstanceOf(param_type)) {
LOG(ERROR) << "JNI ERROR (app bug): attempt to pass an instance of "
@@ -423,7 +425,7 @@
}
}
-static ArtMethod* FindVirtualMethod(mirror::Object* receiver, ArtMethod* method)
+static ArtMethod* FindVirtualMethod(ObjPtr<mirror::Object> receiver, ArtMethod* method)
REQUIRES_SHARED(Locks::mutator_lock_) {
return receiver->GetClass()->FindVirtualMethodForVirtualOrInterface(method, kRuntimePointerSize);
}
@@ -457,7 +459,7 @@
// Replace calls to String.<init> with equivalent StringFactory call.
method = WellKnownClasses::StringInitToStringFactory(method);
}
- mirror::Object* receiver = method->IsStatic() ? nullptr : soa.Decode<mirror::Object*>(obj);
+ ObjPtr<mirror::Object> receiver = method->IsStatic() ? nullptr : soa.Decode<mirror::Object>(obj);
uint32_t shorty_len = 0;
const char* shorty =
method->GetInterfaceMethodIfProxy(kRuntimePointerSize)->GetShorty(&shorty_len);
@@ -488,7 +490,7 @@
// Replace calls to String.<init> with equivalent StringFactory call.
method = WellKnownClasses::StringInitToStringFactory(method);
}
- mirror::Object* receiver = method->IsStatic() ? nullptr : soa.Decode<mirror::Object*>(obj);
+ ObjPtr<mirror::Object> receiver = method->IsStatic() ? nullptr : soa.Decode<mirror::Object>(obj);
uint32_t shorty_len = 0;
const char* shorty =
method->GetInterfaceMethodIfProxy(kRuntimePointerSize)->GetShorty(&shorty_len);
@@ -513,7 +515,7 @@
return JValue();
}
- mirror::Object* receiver = soa.Decode<mirror::Object*>(obj);
+ ObjPtr<mirror::Object> receiver = soa.Decode<mirror::Object>(obj);
ArtMethod* method = FindVirtualMethod(receiver, soa.DecodeMethod(mid));
bool is_string_init = method->GetDeclaringClass()->IsStringClass() && method->IsConstructor();
if (is_string_init) {
@@ -545,7 +547,7 @@
return JValue();
}
- mirror::Object* receiver = soa.Decode<mirror::Object*>(obj);
+ ObjPtr<mirror::Object> receiver = soa.Decode<mirror::Object>(obj);
ArtMethod* method = FindVirtualMethod(receiver, soa.DecodeMethod(mid));
bool is_string_init = method->GetDeclaringClass()->IsStringClass() && method->IsConstructor();
if (is_string_init) {
@@ -578,21 +580,20 @@
return nullptr;
}
- auto* executable = soa.Decode<mirror::Executable*>(javaMethod);
+ ObjPtr<mirror::Executable> executable = soa.Decode<mirror::Executable>(javaMethod);
const bool accessible = executable->IsAccessible();
ArtMethod* m = executable->GetArtMethod();
- mirror::Class* declaring_class = m->GetDeclaringClass();
+ ObjPtr<mirror::Class> declaring_class = m->GetDeclaringClass();
if (UNLIKELY(!declaring_class->IsInitialized())) {
StackHandleScope<1> hs(soa.Self());
- Handle<mirror::Class> h_class(hs.NewHandle(declaring_class));
+ HandleWrapperObjPtr<mirror::Class> h_class(hs.NewHandleWrapper(&declaring_class));
if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(soa.Self(), h_class, true, true)) {
return nullptr;
}
- declaring_class = h_class.Get();
}
- mirror::Object* receiver = nullptr;
+ ObjPtr<mirror::Object> receiver;
if (!m->IsStatic()) {
// Replace calls to String.<init> with equivalent StringFactory call.
if (declaring_class->IsStringClass() && m->IsConstructor()) {
@@ -600,7 +601,7 @@
CHECK(javaReceiver == nullptr);
} else {
// Check that the receiver is non-null and an instance of the field's declaring class.
- receiver = soa.Decode<mirror::Object*>(javaReceiver);
+ receiver = soa.Decode<mirror::Object>(javaReceiver);
if (!VerifyObjectIsClass(receiver, declaring_class)) {
return nullptr;
}
@@ -611,7 +612,8 @@
}
// Get our arrays of arguments and their types, and check they're the same size.
- auto* objects = soa.Decode<mirror::ObjectArray<mirror::Object>*>(javaArgs);
+ ObjPtr<mirror::ObjectArray<mirror::Object>> objects =
+ soa.Decode<mirror::ObjectArray<mirror::Object>>(javaArgs);
auto* np_method = m->GetInterfaceMethodIfProxy(kRuntimePointerSize);
const DexFile::TypeList* classes = np_method->GetParameterTypeList();
uint32_t classes_size = (classes == nullptr) ? 0 : classes->Size();
@@ -623,7 +625,7 @@
}
// If method is not set to be accessible, verify it can be accessed by the caller.
- mirror::Class* calling_class = nullptr;
+ ObjPtr<mirror::Class> calling_class;
if (!accessible && !VerifyAccess(soa.Self(),
receiver,
declaring_class,
@@ -674,12 +676,13 @@
}
// Box if necessary and return.
- return soa.AddLocalReference<jobject>(BoxPrimitive(Primitive::GetType(shorty[0]), result));
+ return soa.AddLocalReference<jobject>(
+ BoxPrimitive(Primitive::GetType(shorty[0]), result).Decode());
}
-mirror::Object* BoxPrimitive(Primitive::Type src_class, const JValue& value) {
+ObjPtr<mirror::Object> BoxPrimitive(Primitive::Type src_class, const JValue& value) {
if (src_class == Primitive::kPrimNot) {
- return value.GetL();
+ return MakeObjPtr(value.GetL());
}
if (src_class == Primitive::kPrimVoid) {
// There's no such thing as a void field, and void methods invoked via reflection return null.
@@ -750,8 +753,9 @@
return "result";
}
-static bool UnboxPrimitive(mirror::Object* o,
- mirror::Class* dst_class, ArtField* f,
+static bool UnboxPrimitive(ObjPtr<mirror::Object> o,
+ ObjPtr<mirror::Class> dst_class,
+ ArtField* f,
JValue* unboxed_value)
REQUIRES_SHARED(Locks::mutator_lock_) {
bool unbox_for_result = (f == nullptr);
@@ -769,7 +773,7 @@
}
return false;
}
- unboxed_value->SetL(o);
+ unboxed_value->SetL(o.Decode());
return true;
}
if (UNLIKELY(dst_class->GetPrimitiveType() == Primitive::kPrimVoid)) {
@@ -791,34 +795,34 @@
}
JValue boxed_value;
- mirror::Class* klass = o->GetClass();
- mirror::Class* src_class = nullptr;
+ ObjPtr<mirror::Class> klass = o->GetClass();
+ ObjPtr<mirror::Class> src_class = nullptr;
ClassLinker* const class_linker = Runtime::Current()->GetClassLinker();
ArtField* primitive_field = &klass->GetIFieldsPtr()->At(0);
if (klass->DescriptorEquals("Ljava/lang/Boolean;")) {
src_class = class_linker->FindPrimitiveClass('Z');
- boxed_value.SetZ(primitive_field->GetBoolean(o));
+ boxed_value.SetZ(primitive_field->GetBoolean(o.Decode()));
} else if (klass->DescriptorEquals("Ljava/lang/Byte;")) {
src_class = class_linker->FindPrimitiveClass('B');
- boxed_value.SetB(primitive_field->GetByte(o));
+ boxed_value.SetB(primitive_field->GetByte(o.Decode()));
} else if (klass->DescriptorEquals("Ljava/lang/Character;")) {
src_class = class_linker->FindPrimitiveClass('C');
- boxed_value.SetC(primitive_field->GetChar(o));
+ boxed_value.SetC(primitive_field->GetChar(o.Decode()));
} else if (klass->DescriptorEquals("Ljava/lang/Float;")) {
src_class = class_linker->FindPrimitiveClass('F');
- boxed_value.SetF(primitive_field->GetFloat(o));
+ boxed_value.SetF(primitive_field->GetFloat(o.Decode()));
} else if (klass->DescriptorEquals("Ljava/lang/Double;")) {
src_class = class_linker->FindPrimitiveClass('D');
- boxed_value.SetD(primitive_field->GetDouble(o));
+ boxed_value.SetD(primitive_field->GetDouble(o.Decode()));
} else if (klass->DescriptorEquals("Ljava/lang/Integer;")) {
src_class = class_linker->FindPrimitiveClass('I');
- boxed_value.SetI(primitive_field->GetInt(o));
+ boxed_value.SetI(primitive_field->GetInt(o.Decode()));
} else if (klass->DescriptorEquals("Ljava/lang/Long;")) {
src_class = class_linker->FindPrimitiveClass('J');
- boxed_value.SetJ(primitive_field->GetLong(o));
+ boxed_value.SetJ(primitive_field->GetLong(o.Decode()));
} else if (klass->DescriptorEquals("Ljava/lang/Short;")) {
src_class = class_linker->FindPrimitiveClass('S');
- boxed_value.SetS(primitive_field->GetShort(o));
+ boxed_value.SetS(primitive_field->GetShort(o.Decode()));
} else {
std::string temp;
ThrowIllegalArgumentException(
@@ -833,28 +837,36 @@
boxed_value, unboxed_value);
}
-bool UnboxPrimitiveForField(mirror::Object* o, mirror::Class* dst_class, ArtField* f,
+bool UnboxPrimitiveForField(ObjPtr<mirror::Object> o,
+ ObjPtr<mirror::Class> dst_class,
+ ArtField* f,
JValue* unboxed_value) {
DCHECK(f != nullptr);
return UnboxPrimitive(o, dst_class, f, unboxed_value);
}
-bool UnboxPrimitiveForResult(mirror::Object* o, mirror::Class* dst_class, JValue* unboxed_value) {
+bool UnboxPrimitiveForResult(ObjPtr<mirror::Object> o,
+ ObjPtr<mirror::Class> dst_class,
+ JValue* unboxed_value) {
return UnboxPrimitive(o, dst_class, nullptr, unboxed_value);
}
-mirror::Class* GetCallingClass(Thread* self, size_t num_frames) {
+ObjPtr<mirror::Class> GetCallingClass(Thread* self, size_t num_frames) {
NthCallerVisitor visitor(self, num_frames);
visitor.WalkStack();
return visitor.caller != nullptr ? visitor.caller->GetDeclaringClass() : nullptr;
}
-bool VerifyAccess(Thread* self, mirror::Object* obj, mirror::Class* declaring_class,
- uint32_t access_flags, mirror::Class** calling_class, size_t num_frames) {
+bool VerifyAccess(Thread* self,
+ ObjPtr<mirror::Object> obj,
+ ObjPtr<mirror::Class> declaring_class,
+ uint32_t access_flags,
+ ObjPtr<mirror::Class>* calling_class,
+ size_t num_frames) {
if ((access_flags & kAccPublic) != 0) {
return true;
}
- auto* klass = GetCallingClass(self, num_frames);
+ ObjPtr<mirror::Class> klass = GetCallingClass(self, num_frames);
if (UNLIKELY(klass == nullptr)) {
// The caller is an attached native thread.
return false;
@@ -863,10 +875,10 @@
return VerifyAccess(obj, declaring_class, access_flags, klass);
}
-bool VerifyAccess(mirror::Object* obj,
- mirror::Class* declaring_class,
+bool VerifyAccess(ObjPtr<mirror::Object> obj,
+ ObjPtr<mirror::Class> declaring_class,
uint32_t access_flags,
- mirror::Class* calling_class) {
+ ObjPtr<mirror::Class> calling_class) {
if (calling_class == declaring_class) {
return true;
}
@@ -876,16 +888,16 @@
}
if ((access_flags & kAccProtected) != 0) {
if (obj != nullptr && !obj->InstanceOf(calling_class) &&
- !declaring_class->IsInSamePackage(calling_class)) {
+ !declaring_class->IsInSamePackage(calling_class.Decode())) {
return false;
- } else if (declaring_class->IsAssignableFrom(calling_class)) {
+ } else if (declaring_class->IsAssignableFrom(calling_class.Decode())) {
return true;
}
}
- return declaring_class->IsInSamePackage(calling_class);
+ return declaring_class->IsInSamePackage(calling_class.Decode());
}
-void InvalidReceiverError(mirror::Object* o, mirror::Class* c) {
+void InvalidReceiverError(ObjPtr<mirror::Object> o, ObjPtr<mirror::Class> c) {
std::string expected_class_name(PrettyDescriptor(c));
std::string actual_class_name(PrettyTypeOf(o));
ThrowIllegalArgumentException(StringPrintf("Expected receiver of type %s, but got %s",
@@ -895,18 +907,18 @@
// This only works if there's one reference which points to the object in obj.
// Will need to be fixed if there's cases where it's not.
-void UpdateReference(Thread* self, jobject obj, mirror::Object* result) {
+void UpdateReference(Thread* self, jobject obj, ObjPtr<mirror::Object> result) {
IndirectRef ref = reinterpret_cast<IndirectRef>(obj);
IndirectRefKind kind = GetIndirectRefKind(ref);
if (kind == kLocal) {
- self->GetJniEnv()->locals.Update(obj, result);
+ self->GetJniEnv()->locals.Update(obj, result.Decode());
} else if (kind == kHandleScopeOrInvalid) {
LOG(FATAL) << "Unsupported UpdateReference for kind kHandleScopeOrInvalid";
} else if (kind == kGlobal) {
- self->GetJniEnv()->vm->UpdateGlobal(self, ref, result);
+ self->GetJniEnv()->vm->UpdateGlobal(self, ref, result.Decode());
} else {
DCHECK_EQ(kind, kWeakGlobal);
- self->GetJniEnv()->vm->UpdateWeakGlobal(self, ref, result);
+ self->GetJniEnv()->vm->UpdateWeakGlobal(self, ref, result.Decode());
}
}
diff --git a/runtime/reflection.h b/runtime/reflection.h
index 208b533..6e5ef71 100644
--- a/runtime/reflection.h
+++ b/runtime/reflection.h
@@ -19,6 +19,7 @@
#include "base/mutex.h"
#include "jni.h"
+#include "obj_ptr.h"
#include "primitive.h"
namespace art {
@@ -32,62 +33,85 @@
class ScopedObjectAccessAlreadyRunnable;
class ShadowFrame;
-mirror::Object* BoxPrimitive(Primitive::Type src_class, const JValue& value)
+ObjPtr<mirror::Object> BoxPrimitive(Primitive::Type src_class, const JValue& value)
REQUIRES_SHARED(Locks::mutator_lock_);
-bool UnboxPrimitiveForField(mirror::Object* o, mirror::Class* dst_class, ArtField* f,
+
+bool UnboxPrimitiveForField(ObjPtr<mirror::Object> o,
+ ObjPtr<mirror::Class> dst_class,
+ ArtField* f,
JValue* unboxed_value)
REQUIRES_SHARED(Locks::mutator_lock_);
-bool UnboxPrimitiveForResult(mirror::Object* o, mirror::Class* dst_class, JValue* unboxed_value)
+
+bool UnboxPrimitiveForResult(ObjPtr<mirror::Object> o,
+ ObjPtr<mirror::Class> dst_class,
+ JValue* unboxed_value)
REQUIRES_SHARED(Locks::mutator_lock_);
ALWAYS_INLINE bool ConvertPrimitiveValue(bool unbox_for_result,
- Primitive::Type src_class, Primitive::Type dst_class,
- const JValue& src, JValue* dst)
+ Primitive::Type src_class,
+ Primitive::Type dst_class,
+ const JValue& src,
+ JValue* dst)
REQUIRES_SHARED(Locks::mutator_lock_);
-JValue InvokeWithVarArgs(const ScopedObjectAccessAlreadyRunnable& soa, jobject obj, jmethodID mid,
+JValue InvokeWithVarArgs(const ScopedObjectAccessAlreadyRunnable& soa,
+ jobject obj,
+ jmethodID mid,
va_list args)
REQUIRES_SHARED(Locks::mutator_lock_);
-JValue InvokeWithJValues(const ScopedObjectAccessAlreadyRunnable& soa, jobject obj, jmethodID mid,
+JValue InvokeWithJValues(const ScopedObjectAccessAlreadyRunnable& soa,
+ jobject obj,
+ jmethodID mid,
jvalue* args)
REQUIRES_SHARED(Locks::mutator_lock_);
JValue InvokeVirtualOrInterfaceWithJValues(const ScopedObjectAccessAlreadyRunnable& soa,
- jobject obj, jmethodID mid, jvalue* args)
+ jobject obj,
+ jmethodID mid,
+ jvalue* args)
REQUIRES_SHARED(Locks::mutator_lock_);
JValue InvokeVirtualOrInterfaceWithVarArgs(const ScopedObjectAccessAlreadyRunnable& soa,
- jobject obj, jmethodID mid, va_list args)
+ jobject obj,
+ jmethodID mid,
+ va_list args)
REQUIRES_SHARED(Locks::mutator_lock_);
// num_frames is number of frames we look up for access check.
-jobject InvokeMethod(const ScopedObjectAccessAlreadyRunnable& soa, jobject method, jobject receiver,
- jobject args, size_t num_frames = 1)
+jobject InvokeMethod(const ScopedObjectAccessAlreadyRunnable& soa,
+ jobject method,
+ jobject receiver,
+ jobject args,
+ size_t num_frames = 1)
REQUIRES_SHARED(Locks::mutator_lock_);
-ALWAYS_INLINE bool VerifyObjectIsClass(mirror::Object* o, mirror::Class* c)
+ALWAYS_INLINE bool VerifyObjectIsClass(ObjPtr<mirror::Object> o, ObjPtr<mirror::Class> c)
REQUIRES_SHARED(Locks::mutator_lock_);
-bool VerifyAccess(Thread* self, mirror::Object* obj, mirror::Class* declaring_class,
- uint32_t access_flags, mirror::Class** calling_class, size_t num_frames)
+bool VerifyAccess(Thread* self,
+ ObjPtr<mirror::Object> obj,
+ ObjPtr<mirror::Class> declaring_class,
+ uint32_t access_flags,
+ ObjPtr<mirror::Class>* calling_class,
+ size_t num_frames)
REQUIRES_SHARED(Locks::mutator_lock_);
// This version takes a known calling class.
-bool VerifyAccess(mirror::Object* obj,
- mirror::Class* declaring_class,
+bool VerifyAccess(ObjPtr<mirror::Object> obj,
+ ObjPtr<mirror::Class> declaring_class,
uint32_t access_flags,
- mirror::Class* calling_class)
+ ObjPtr<mirror::Class> calling_class)
REQUIRES_SHARED(Locks::mutator_lock_);
// Get the calling class by using a stack visitor, may return null for unattached native threads.
-mirror::Class* GetCallingClass(Thread* self, size_t num_frames)
+ObjPtr<mirror::Class> GetCallingClass(Thread* self, size_t num_frames)
REQUIRES_SHARED(Locks::mutator_lock_);
-void InvalidReceiverError(mirror::Object* o, mirror::Class* c)
+void InvalidReceiverError(ObjPtr<mirror::Object> o, ObjPtr<mirror::Class> c)
REQUIRES_SHARED(Locks::mutator_lock_);
-void UpdateReference(Thread* self, jobject obj, mirror::Object* result)
+void UpdateReference(Thread* self, jobject obj, ObjPtr<mirror::Object> result)
REQUIRES_SHARED(Locks::mutator_lock_);
} // namespace art
diff --git a/runtime/reflection_test.cc b/runtime/reflection_test.cc
index 4876ff0..189ed03 100644
--- a/runtime/reflection_test.cc
+++ b/runtime/reflection_test.cc
@@ -23,7 +23,7 @@
#include "art_method-inl.h"
#include "base/enums.h"
#include "common_compiler_test.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
namespace art {
@@ -93,16 +93,12 @@
StackHandleScope<2> hs(self);
Handle<mirror::ClassLoader> class_loader(
hs.NewHandle(
- ScopedObjectAccessUnchecked(self).Decode<mirror::ClassLoader*>(jclass_loader)));
- if (is_static) {
- MakeExecutable(ScopedObjectAccessUnchecked(self).Decode<mirror::ClassLoader*>(jclass_loader),
- class_name);
- } else {
+ ScopedObjectAccessUnchecked(self).Decode<mirror::ClassLoader>(jclass_loader)));
+ if (!is_static) {
MakeExecutable(nullptr, "java.lang.Class");
MakeExecutable(nullptr, "java.lang.Object");
- MakeExecutable(ScopedObjectAccessUnchecked(self).Decode<mirror::ClassLoader*>(jclass_loader),
- class_name);
}
+ MakeExecutable(class_loader.Get(), class_name);
mirror::Class* c = class_linker_->FindClass(self, DotToDescriptor(class_name).c_str(),
class_loader);
@@ -512,7 +508,7 @@
jobject jclass_loader = LoadDex("Main");
StackHandleScope<1> hs(soa.Self());
Handle<mirror::ClassLoader> class_loader(
- hs.NewHandle(soa.Decode<mirror::ClassLoader*>(jclass_loader)));
+ hs.NewHandle(soa.Decode<mirror::ClassLoader>(jclass_loader)));
CompileDirectMethod(class_loader, "Main", "main", "([Ljava/lang/String;)V");
mirror::Class* klass = class_linker_->FindClass(soa.Self(), "LMain;", class_loader);
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 5bb38f5..df0dca0 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -88,6 +88,8 @@
#include "mirror/class_loader.h"
#include "mirror/field.h"
#include "mirror/method.h"
+#include "mirror/method_handle_impl.h"
+#include "mirror/method_type.h"
#include "mirror/stack_trace_element.h"
#include "mirror/throwable.h"
#include "monitor.h"
@@ -131,7 +133,7 @@
#include "reflection.h"
#include "runtime_options.h"
#include "ScopedLocalRef.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
#include "sigchain.h"
#include "signal_catcher.h"
#include "signal_set.h"
@@ -528,7 +530,7 @@
StackHandleScope<2> hs(soa.Self());
Handle<mirror::Class> class_loader_class(
- hs.NewHandle(soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_ClassLoader)));
+ hs.NewHandle(soa.Decode<mirror::Class>(WellKnownClasses::java_lang_ClassLoader)));
CHECK(cl->EnsureInitialized(soa.Self(), class_loader_class, true, true));
ArtMethod* getSystemClassLoader = class_loader_class->FindDirectMethod(
@@ -543,7 +545,7 @@
soa.Self()->SetClassLoaderOverride(system_class_loader.get());
Handle<mirror::Class> thread_class(
- hs.NewHandle(soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_Thread)));
+ hs.NewHandle(soa.Decode<mirror::Class>(WellKnownClasses::java_lang_Thread)));
CHECK(cl->EnsureInitialized(soa.Self(), thread_class, true, true));
ArtField* contextClassLoader =
@@ -551,8 +553,9 @@
CHECK(contextClassLoader != nullptr);
// We can't run in a transaction yet.
- contextClassLoader->SetObject<false>(soa.Self()->GetPeer(),
- soa.Decode<mirror::ClassLoader*>(system_class_loader.get()));
+ contextClassLoader->SetObject<false>(
+ soa.Self()->GetPeer(),
+ soa.Decode<mirror::ClassLoader>(system_class_loader.get()).Decode());
return env->NewGlobalRef(system_class_loader.get());
}
@@ -1547,6 +1550,8 @@
mirror::String::VisitRoots(visitor);
mirror::Throwable::VisitRoots(visitor);
mirror::Field::VisitRoots(visitor);
+ mirror::MethodType::VisitRoots(visitor);
+ mirror::MethodHandleImpl::VisitRoots(visitor);
// Visit all the primitive array types classes.
mirror::PrimitiveArray<uint8_t>::VisitRoots(visitor); // BooleanArray
mirror::PrimitiveArray<int8_t>::VisitRoots(visitor); // ByteArray
diff --git a/runtime/scoped_thread_state_change-inl.h b/runtime/scoped_thread_state_change-inl.h
new file mode 100644
index 0000000..cf020d0
--- /dev/null
+++ b/runtime/scoped_thread_state_change-inl.h
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_RUNTIME_SCOPED_THREAD_STATE_CHANGE_INL_H_
+#define ART_RUNTIME_SCOPED_THREAD_STATE_CHANGE_INL_H_
+
+#include "scoped_thread_state_change.h"
+
+#include "jni_env_ext-inl.h"
+#include "obj_ptr-inl.h"
+#include "thread-inl.h"
+
+namespace art {
+
+inline ScopedThreadStateChange::ScopedThreadStateChange(Thread* self, ThreadState new_thread_state)
+ : self_(self), thread_state_(new_thread_state), expected_has_no_thread_(false) {
+ if (UNLIKELY(self_ == nullptr)) {
+ // Value chosen arbitrarily and won't be used in the destructor since thread_ == null.
+ old_thread_state_ = kTerminated;
+ Runtime* runtime = Runtime::Current();
+ CHECK(runtime == nullptr || !runtime->IsStarted() || runtime->IsShuttingDown(self_));
+ } else {
+ DCHECK_EQ(self, Thread::Current());
+ // Read state without locks, ok as state is effectively thread local and we're not interested
+ // in the suspend count (this will be handled in the runnable transitions).
+ old_thread_state_ = self->GetState();
+ if (old_thread_state_ != new_thread_state) {
+ if (new_thread_state == kRunnable) {
+ self_->TransitionFromSuspendedToRunnable();
+ } else if (old_thread_state_ == kRunnable) {
+ self_->TransitionFromRunnableToSuspended(new_thread_state);
+ } else {
+ // A suspended transition to another effectively suspended transition, ok to use Unsafe.
+ self_->SetState(new_thread_state);
+ }
+ }
+ }
+}
+
+inline ScopedThreadStateChange::~ScopedThreadStateChange() {
+ if (UNLIKELY(self_ == nullptr)) {
+ if (!expected_has_no_thread_) {
+ Runtime* runtime = Runtime::Current();
+ bool shutting_down = (runtime == nullptr) || runtime->IsShuttingDown(nullptr);
+ CHECK(shutting_down);
+ }
+ } else {
+ if (old_thread_state_ != thread_state_) {
+ if (old_thread_state_ == kRunnable) {
+ self_->TransitionFromSuspendedToRunnable();
+ } else if (thread_state_ == kRunnable) {
+ self_->TransitionFromRunnableToSuspended(old_thread_state_);
+ } else {
+ // A suspended transition to another effectively suspended transition, ok to use Unsafe.
+ self_->SetState(old_thread_state_);
+ }
+ }
+ }
+}
+
+template<typename T>
+inline T ScopedObjectAccessAlreadyRunnable::AddLocalReference(mirror::Object* obj) const {
+ Locks::mutator_lock_->AssertSharedHeld(Self());
+ DCHECK(IsRunnable()); // Don't work with raw objects in non-runnable states.
+ DCHECK_NE(obj, Runtime::Current()->GetClearedJniWeakGlobal());
+ return obj == nullptr ? nullptr : Env()->AddLocalReference<T>(obj);
+}
+
+template<typename T, typename MirrorType, bool kPoison>
+inline T ScopedObjectAccessAlreadyRunnable::AddLocalReference(
+ ObjPtr<MirrorType, kPoison> obj) const {
+ return AddLocalReference<T>(obj.Decode());
+}
+
+template<typename T, bool kPoison>
+inline ObjPtr<T, kPoison> ScopedObjectAccessAlreadyRunnable::Decode(jobject obj) const {
+ Locks::mutator_lock_->AssertSharedHeld(Self());
+ DCHECK(IsRunnable()); // Don't work with raw objects in non-runnable states.
+ return down_cast<T*>(Self()->DecodeJObject(obj));
+}
+
+inline ArtField* ScopedObjectAccessAlreadyRunnable::DecodeField(jfieldID fid) const {
+ Locks::mutator_lock_->AssertSharedHeld(Self());
+ DCHECK(IsRunnable()); // Don't work with raw objects in non-runnable states.
+ return reinterpret_cast<ArtField*>(fid);
+}
+
+inline jfieldID ScopedObjectAccessAlreadyRunnable::EncodeField(ArtField* field) const {
+ Locks::mutator_lock_->AssertSharedHeld(Self());
+ DCHECK(IsRunnable()); // Don't work with raw objects in non-runnable states.
+ return reinterpret_cast<jfieldID>(field);
+}
+
+inline ArtMethod* ScopedObjectAccessAlreadyRunnable::DecodeMethod(jmethodID mid) const {
+ Locks::mutator_lock_->AssertSharedHeld(Self());
+ DCHECK(IsRunnable()); // Don't work with raw objects in non-runnable states.
+ return reinterpret_cast<ArtMethod*>(mid);
+}
+
+inline jmethodID ScopedObjectAccessAlreadyRunnable::EncodeMethod(ArtMethod* method) const {
+ Locks::mutator_lock_->AssertSharedHeld(Self());
+ DCHECK(IsRunnable()); // Don't work with raw objects in non-runnable states.
+ return reinterpret_cast<jmethodID>(method);
+}
+
+inline bool ScopedObjectAccessAlreadyRunnable::IsRunnable() const {
+ return self_->GetState() == kRunnable;
+}
+
+inline ScopedObjectAccessAlreadyRunnable::ScopedObjectAccessAlreadyRunnable(JNIEnv* env)
+ : self_(ThreadForEnv(env)), env_(down_cast<JNIEnvExt*>(env)), vm_(env_->vm) {}
+
+inline ScopedObjectAccessAlreadyRunnable::ScopedObjectAccessAlreadyRunnable(Thread* self)
+ : self_(self),
+ env_(down_cast<JNIEnvExt*>(self->GetJniEnv())),
+ vm_(env_ != nullptr ? env_->vm : nullptr) {}
+
+inline ScopedObjectAccessUnchecked::ScopedObjectAccessUnchecked(JNIEnv* env)
+ : ScopedObjectAccessAlreadyRunnable(env), tsc_(Self(), kRunnable) {
+ Self()->VerifyStack();
+ Locks::mutator_lock_->AssertSharedHeld(Self());
+}
+
+inline ScopedObjectAccessUnchecked::ScopedObjectAccessUnchecked(Thread* self)
+ : ScopedObjectAccessAlreadyRunnable(self), tsc_(self, kRunnable) {
+ Self()->VerifyStack();
+ Locks::mutator_lock_->AssertSharedHeld(Self());
+}
+
+inline ScopedThreadSuspension::ScopedThreadSuspension(Thread* self, ThreadState suspended_state)
+ : self_(self), suspended_state_(suspended_state) {
+ DCHECK(self_ != nullptr);
+ self_->TransitionFromRunnableToSuspended(suspended_state);
+}
+
+inline ScopedThreadSuspension::~ScopedThreadSuspension() {
+ DCHECK_EQ(self_->GetState(), suspended_state_);
+ self_->TransitionFromSuspendedToRunnable();
+}
+
+} // namespace art
+
+#endif // ART_RUNTIME_SCOPED_THREAD_STATE_CHANGE_INL_H_
diff --git a/runtime/scoped_thread_state_change.h b/runtime/scoped_thread_state_change.h
index 8a1aca5..175bec5 100644
--- a/runtime/scoped_thread_state_change.h
+++ b/runtime/scoped_thread_state_change.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012 The Android Open Source Project
+ * Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,85 +17,43 @@
#ifndef ART_RUNTIME_SCOPED_THREAD_STATE_CHANGE_H_
#define ART_RUNTIME_SCOPED_THREAD_STATE_CHANGE_H_
-#include "base/casts.h"
-#include "java_vm_ext.h"
-#include "jni_env_ext-inl.h"
#include "art_field.h"
-#include "read_barrier.h"
-#include "thread-inl.h"
+#include "base/casts.h"
+#include "base/value_object.h"
+#include "java_vm_ext.h"
+#include "thread_state.h"
#include "verify_object.h"
namespace art {
+struct JNIEnvExt;
+template<class MirrorType, bool kPoison> class ObjPtr;
+
// Scoped change into and out of a particular state. Handles Runnable transitions that require
// more complicated suspension checking. The subclasses ScopedObjectAccessUnchecked and
// ScopedObjectAccess are used to handle the change into Runnable to Get direct access to objects,
// the unchecked variant doesn't aid annotalysis.
class ScopedThreadStateChange : public ValueObject {
public:
- ScopedThreadStateChange(Thread* self, ThreadState new_thread_state)
- REQUIRES(!Locks::thread_suspend_count_lock_) ALWAYS_INLINE
- : self_(self), thread_state_(new_thread_state), expected_has_no_thread_(false) {
- if (UNLIKELY(self_ == nullptr)) {
- // Value chosen arbitrarily and won't be used in the destructor since thread_ == null.
- old_thread_state_ = kTerminated;
- Runtime* runtime = Runtime::Current();
- CHECK(runtime == nullptr || !runtime->IsStarted() || runtime->IsShuttingDown(self_));
- } else {
- DCHECK_EQ(self, Thread::Current());
- // Read state without locks, ok as state is effectively thread local and we're not interested
- // in the suspend count (this will be handled in the runnable transitions).
- old_thread_state_ = self->GetState();
- if (old_thread_state_ != new_thread_state) {
- if (new_thread_state == kRunnable) {
- self_->TransitionFromSuspendedToRunnable();
- } else if (old_thread_state_ == kRunnable) {
- self_->TransitionFromRunnableToSuspended(new_thread_state);
- } else {
- // A suspended transition to another effectively suspended transition, ok to use Unsafe.
- self_->SetState(new_thread_state);
- }
- }
- }
- }
+ ALWAYS_INLINE ScopedThreadStateChange(Thread* self, ThreadState new_thread_state)
+ REQUIRES(!Locks::thread_suspend_count_lock_);
- ~ScopedThreadStateChange() REQUIRES(!Locks::thread_suspend_count_lock_) ALWAYS_INLINE {
- if (UNLIKELY(self_ == nullptr)) {
- if (!expected_has_no_thread_) {
- Runtime* runtime = Runtime::Current();
- bool shutting_down = (runtime == nullptr) || runtime->IsShuttingDown(nullptr);
- CHECK(shutting_down);
- }
- } else {
- if (old_thread_state_ != thread_state_) {
- if (old_thread_state_ == kRunnable) {
- self_->TransitionFromSuspendedToRunnable();
- } else if (thread_state_ == kRunnable) {
- self_->TransitionFromRunnableToSuspended(old_thread_state_);
- } else {
- // A suspended transition to another effectively suspended transition, ok to use Unsafe.
- self_->SetState(old_thread_state_);
- }
- }
- }
- }
+ ALWAYS_INLINE ~ScopedThreadStateChange() REQUIRES(!Locks::thread_suspend_count_lock_);
- Thread* Self() const {
+ ALWAYS_INLINE Thread* Self() const {
return self_;
}
protected:
// Constructor used by ScopedJniThreadState for an unattached thread that has access to the VM*.
- ScopedThreadStateChange()
- : self_(nullptr), thread_state_(kTerminated), old_thread_state_(kTerminated),
- expected_has_no_thread_(true) {}
+ ScopedThreadStateChange() {}
- Thread* const self_;
- const ThreadState thread_state_;
+ Thread* const self_ = nullptr;
+ const ThreadState thread_state_ = kTerminated;
private:
- ThreadState old_thread_state_;
- const bool expected_has_no_thread_;
+ ThreadState old_thread_state_ = kTerminated;
+ const bool expected_has_no_thread_ = true;
friend class ScopedObjectAccessUnchecked;
DISALLOW_COPY_AND_ASSIGN(ScopedThreadStateChange);
@@ -129,62 +87,34 @@
* This will be called on otherwise unreferenced objects. We cannot do GC allocations here, and
* it's best if we don't grab a mutex.
*/
+ template<typename T, typename MirrorType, bool kPoison = kIsDebugBuild>
+ T AddLocalReference(ObjPtr<MirrorType, kPoison> obj) const
+ REQUIRES_SHARED(Locks::mutator_lock_);
+
+ // TODO: Delete
template<typename T>
- T AddLocalReference(mirror::Object* obj) const REQUIRES_SHARED(Locks::mutator_lock_) {
- Locks::mutator_lock_->AssertSharedHeld(Self());
- DCHECK(IsRunnable()); // Don't work with raw objects in non-runnable states.
- DCHECK_NE(obj, Runtime::Current()->GetClearedJniWeakGlobal());
- return obj == nullptr ? nullptr : Env()->AddLocalReference<T>(obj);
- }
+ T AddLocalReference(mirror::Object* obj) const
+ REQUIRES_SHARED(Locks::mutator_lock_);
- template<typename T>
- T Decode(jobject obj) const
- REQUIRES_SHARED(Locks::mutator_lock_) {
- Locks::mutator_lock_->AssertSharedHeld(Self());
- DCHECK(IsRunnable()); // Don't work with raw objects in non-runnable states.
- return down_cast<T>(Self()->DecodeJObject(obj));
- }
+ template<typename T, bool kPoison = kIsDebugBuild>
+ ObjPtr<T, kPoison> Decode(jobject obj) const REQUIRES_SHARED(Locks::mutator_lock_);
- ArtField* DecodeField(jfieldID fid) const
- REQUIRES_SHARED(Locks::mutator_lock_) {
- Locks::mutator_lock_->AssertSharedHeld(Self());
- DCHECK(IsRunnable()); // Don't work with raw objects in non-runnable states.
- return reinterpret_cast<ArtField*>(fid);
- }
+ ArtField* DecodeField(jfieldID fid) const REQUIRES_SHARED(Locks::mutator_lock_);
- jfieldID EncodeField(ArtField* field) const REQUIRES_SHARED(Locks::mutator_lock_) {
- Locks::mutator_lock_->AssertSharedHeld(Self());
- DCHECK(IsRunnable()); // Don't work with raw objects in non-runnable states.
- return reinterpret_cast<jfieldID>(field);
- }
+ jfieldID EncodeField(ArtField* field) const REQUIRES_SHARED(Locks::mutator_lock_);
- ArtMethod* DecodeMethod(jmethodID mid) const REQUIRES_SHARED(Locks::mutator_lock_) {
- Locks::mutator_lock_->AssertSharedHeld(Self());
- DCHECK(IsRunnable()); // Don't work with raw objects in non-runnable states.
- return reinterpret_cast<ArtMethod*>(mid);
- }
+ ArtMethod* DecodeMethod(jmethodID mid) const REQUIRES_SHARED(Locks::mutator_lock_);
- jmethodID EncodeMethod(ArtMethod* method) const REQUIRES_SHARED(Locks::mutator_lock_) {
- Locks::mutator_lock_->AssertSharedHeld(Self());
- DCHECK(IsRunnable()); // Don't work with raw objects in non-runnable states.
- return reinterpret_cast<jmethodID>(method);
- }
+ jmethodID EncodeMethod(ArtMethod* method) const REQUIRES_SHARED(Locks::mutator_lock_);
- bool IsRunnable() const {
- return self_->GetState() == kRunnable;
- }
+ ALWAYS_INLINE bool IsRunnable() const;
protected:
- explicit ScopedObjectAccessAlreadyRunnable(JNIEnv* env)
- REQUIRES(!Locks::thread_suspend_count_lock_) ALWAYS_INLINE
- : self_(ThreadForEnv(env)), env_(down_cast<JNIEnvExt*>(env)), vm_(env_->vm) {
- }
+ ALWAYS_INLINE explicit ScopedObjectAccessAlreadyRunnable(JNIEnv* env)
+ REQUIRES(!Locks::thread_suspend_count_lock_);
- explicit ScopedObjectAccessAlreadyRunnable(Thread* self)
- REQUIRES(!Locks::thread_suspend_count_lock_) ALWAYS_INLINE
- : self_(self), env_(down_cast<JNIEnvExt*>(self->GetJniEnv())),
- vm_(env_ != nullptr ? env_->vm : nullptr) {
- }
+ ALWAYS_INLINE explicit ScopedObjectAccessAlreadyRunnable(Thread* self)
+ REQUIRES(!Locks::thread_suspend_count_lock_);
// Used when we want a scoped JNI thread state but have no thread/JNIEnv. Consequently doesn't
// change into Runnable or acquire a share on the mutator_lock_.
@@ -192,8 +122,7 @@
: self_(nullptr), env_(nullptr), vm_(down_cast<JavaVMExt*>(vm)) {}
// Here purely to force inlining.
- ~ScopedObjectAccessAlreadyRunnable() ALWAYS_INLINE {
- }
+ ALWAYS_INLINE ~ScopedObjectAccessAlreadyRunnable() {}
// Self thread, can be null.
Thread* const self_;
@@ -219,19 +148,11 @@
// the mutator_lock_ will be acquired on construction.
class ScopedObjectAccessUnchecked : public ScopedObjectAccessAlreadyRunnable {
public:
- explicit ScopedObjectAccessUnchecked(JNIEnv* env)
- REQUIRES(!Locks::thread_suspend_count_lock_) ALWAYS_INLINE
- : ScopedObjectAccessAlreadyRunnable(env), tsc_(Self(), kRunnable) {
- Self()->VerifyStack();
- Locks::mutator_lock_->AssertSharedHeld(Self());
- }
+ ALWAYS_INLINE explicit ScopedObjectAccessUnchecked(JNIEnv* env)
+ REQUIRES(!Locks::thread_suspend_count_lock_);
- explicit ScopedObjectAccessUnchecked(Thread* self)
- REQUIRES(!Locks::thread_suspend_count_lock_) ALWAYS_INLINE
- : ScopedObjectAccessAlreadyRunnable(self), tsc_(self, kRunnable) {
- Self()->VerifyStack();
- Locks::mutator_lock_->AssertSharedHeld(Self());
- }
+ ALWAYS_INLINE explicit ScopedObjectAccessUnchecked(Thread* self)
+ REQUIRES(!Locks::thread_suspend_count_lock_);
// Used when we want a scoped JNI thread state but have no thread/JNIEnv. Consequently doesn't
// change into Runnable or acquire a share on the mutator_lock_.
@@ -249,28 +170,24 @@
// Annotalysis helping variant of the above.
class ScopedObjectAccess : public ScopedObjectAccessUnchecked {
public:
- explicit ScopedObjectAccess(JNIEnv* env)
+ ALWAYS_INLINE explicit ScopedObjectAccess(JNIEnv* env)
REQUIRES(!Locks::thread_suspend_count_lock_)
- SHARED_LOCK_FUNCTION(Locks::mutator_lock_) ALWAYS_INLINE
- : ScopedObjectAccessUnchecked(env) {
- }
+ SHARED_LOCK_FUNCTION(Locks::mutator_lock_)
+ : ScopedObjectAccessUnchecked(env) {}
- explicit ScopedObjectAccess(Thread* self)
+ ALWAYS_INLINE explicit ScopedObjectAccess(Thread* self)
REQUIRES(!Locks::thread_suspend_count_lock_)
- SHARED_LOCK_FUNCTION(Locks::mutator_lock_) ALWAYS_INLINE
- : ScopedObjectAccessUnchecked(self) {
- }
+ SHARED_LOCK_FUNCTION(Locks::mutator_lock_)
+ : ScopedObjectAccessUnchecked(self) {}
- ~ScopedObjectAccess() UNLOCK_FUNCTION(Locks::mutator_lock_) ALWAYS_INLINE {
- // Base class will release share of lock. Invoked after this destructor.
- }
+ // Base class will release share of lock. Invoked after this destructor.
+ ~ScopedObjectAccess() UNLOCK_FUNCTION(Locks::mutator_lock_) ALWAYS_INLINE {}
private:
// TODO: remove this constructor. It is used by check JNI's ScopedCheck to make it believe that
// routines operating with just a VM are sound, they are not, but when you have just a VM
// you cannot call the unsound routines.
- explicit ScopedObjectAccess(JavaVM* vm)
- SHARED_LOCK_FUNCTION(Locks::mutator_lock_)
+ explicit ScopedObjectAccess(JavaVM* vm) SHARED_LOCK_FUNCTION(Locks::mutator_lock_)
: ScopedObjectAccessUnchecked(vm) {}
friend class ScopedCheck;
@@ -280,19 +197,11 @@
// Annotalysis helper for going to a suspended state from runnable.
class ScopedThreadSuspension : public ValueObject {
public:
- explicit ScopedThreadSuspension(Thread* self, ThreadState suspended_state)
+ ALWAYS_INLINE explicit ScopedThreadSuspension(Thread* self, ThreadState suspended_state)
REQUIRES(!Locks::thread_suspend_count_lock_, !Roles::uninterruptible_)
- UNLOCK_FUNCTION(Locks::mutator_lock_)
- ALWAYS_INLINE
- : self_(self), suspended_state_(suspended_state) {
- DCHECK(self_ != nullptr);
- self_->TransitionFromRunnableToSuspended(suspended_state);
- }
+ UNLOCK_FUNCTION(Locks::mutator_lock_);
- ~ScopedThreadSuspension() SHARED_LOCK_FUNCTION(Locks::mutator_lock_) ALWAYS_INLINE {
- DCHECK_EQ(self_->GetState(), suspended_state_);
- self_->TransitionFromSuspendedToRunnable();
- }
+ ALWAYS_INLINE ~ScopedThreadSuspension() SHARED_LOCK_FUNCTION(Locks::mutator_lock_);
private:
Thread* const self_;
diff --git a/runtime/signal_catcher.cc b/runtime/signal_catcher.cc
index 848c0e3..674459d 100644
--- a/runtime/signal_catcher.cc
+++ b/runtime/signal_catcher.cc
@@ -34,7 +34,7 @@
#include "gc/heap.h"
#include "os.h"
#include "runtime.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
#include "signal_set.h"
#include "thread.h"
#include "thread_list.h"
diff --git a/runtime/thread-inl.h b/runtime/thread-inl.h
index 298a974..bb6eb79 100644
--- a/runtime/thread-inl.h
+++ b/runtime/thread-inl.h
@@ -59,6 +59,8 @@
if (UNLIKELY(TestAllFlags())) {
CheckSuspend();
}
+ // Invalidate the current thread's object pointers (ObjPtr) to catch possible moving GC bugs due
+ // to missing handles.
PoisonObjectPointers();
}
@@ -173,6 +175,9 @@
inline void Thread::TransitionFromRunnableToSuspended(ThreadState new_state) {
AssertThreadSuspensionIsAllowable();
+ if (kIsDebugBuild) {
+ PoisonObjectPointers();
+ }
DCHECK_EQ(this, Thread::Current());
// Change to non-runnable state, thereby appearing suspended to the system.
TransitionToSuspendedAndRunCheckpoints(new_state);
@@ -303,6 +308,12 @@
tlsPtr_.thread_local_alloc_stack_top = nullptr;
}
+inline void Thread::PoisonObjectPointersIfDebug() {
+ if (kIsDebugBuild) {
+ Thread::Current()->PoisonObjectPointers();
+ }
+}
+
} // namespace art
#endif // ART_RUNTIME_THREAD_INL_H_
diff --git a/runtime/thread.cc b/runtime/thread.cc
index d0ea2d7..ec1bb3f 100644
--- a/runtime/thread.cc
+++ b/runtime/thread.cc
@@ -59,12 +59,13 @@
#include "native_stack_dump.h"
#include "nth_caller_visitor.h"
#include "oat_quick_method_header.h"
+#include "obj_ptr-inl.h"
#include "object_lock.h"
#include "quick_exception_handler.h"
#include "quick/quick_method_frame_info.h"
#include "reflection.h"
#include "runtime.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
#include "ScopedLocalRef.h"
#include "ScopedUtfChars.h"
#include "stack.h"
@@ -406,7 +407,7 @@
// Copy peer into self, deleting global reference when done.
CHECK(self->tlsPtr_.jpeer != nullptr);
- self->tlsPtr_.opeer = soa.Decode<mirror::Object*>(self->tlsPtr_.jpeer);
+ self->tlsPtr_.opeer = soa.Decode<mirror::Object>(self->tlsPtr_.jpeer).Decode();
self->GetJniEnv()->DeleteGlobalRef(self->tlsPtr_.jpeer);
self->tlsPtr_.jpeer = nullptr;
self->SetThreadName(self->GetThreadName(soa)->ToModifiedUtf8().c_str());
@@ -444,7 +445,7 @@
Thread* Thread::FromManagedThread(const ScopedObjectAccessAlreadyRunnable& soa,
jobject java_thread) {
- return FromManagedThread(soa, soa.Decode<mirror::Object*>(java_thread));
+ return FromManagedThread(soa, soa.Decode<mirror::Object>(java_thread).Decode());
}
static size_t FixStackSize(size_t stack_size) {
@@ -563,7 +564,7 @@
ArtField* f = soa.DecodeField(WellKnownClasses::java_lang_Thread_name);
mirror::String* java_name = reinterpret_cast<mirror::String*>(f->GetObject(
- soa.Decode<mirror::Object*>(java_peer)));
+ soa.Decode<mirror::Object>(java_peer).Decode()));
std::string thread_name;
if (java_name != nullptr) {
thread_name = java_name->ToModifiedUtf8();
@@ -802,7 +803,7 @@
}
{
ScopedObjectAccess soa(this);
- tlsPtr_.opeer = soa.Decode<mirror::Object*>(peer.get());
+ tlsPtr_.opeer = soa.Decode<mirror::Object>(peer.get()).Decode();
}
env->CallNonvirtualVoidMethod(peer.get(),
WellKnownClasses::java_lang_Thread,
@@ -844,9 +845,11 @@
soa.DecodeField(WellKnownClasses::java_lang_Thread_daemon)->
SetBoolean<kTransactionActive>(tlsPtr_.opeer, thread_is_daemon);
soa.DecodeField(WellKnownClasses::java_lang_Thread_group)->
- SetObject<kTransactionActive>(tlsPtr_.opeer, soa.Decode<mirror::Object*>(thread_group));
+ SetObject<kTransactionActive>(tlsPtr_.opeer,
+ soa.Decode<mirror::Object>(thread_group).Decode());
soa.DecodeField(WellKnownClasses::java_lang_Thread_name)->
- SetObject<kTransactionActive>(tlsPtr_.opeer, soa.Decode<mirror::Object*>(thread_name));
+ SetObject<kTransactionActive>(tlsPtr_.opeer,
+ soa.Decode<mirror::Object>(thread_name).Decode());
soa.DecodeField(WellKnownClasses::java_lang_Thread_priority)->
SetInt<kTransactionActive>(tlsPtr_.opeer, thread_priority);
}
@@ -2123,7 +2126,7 @@
int* stack_depth) {
// Decode the internal stack trace into the depth, method trace and PC trace.
// Subtract one for the methods and PC trace.
- int32_t depth = soa.Decode<mirror::Array*>(internal)->GetLength() - 1;
+ int32_t depth = soa.Decode<mirror::Array>(internal)->GetLength() - 1;
DCHECK_GE(depth, 0);
ClassLinker* const class_linker = Runtime::Current()->GetClassLinker();
@@ -2135,7 +2138,7 @@
result = output_array;
// ...adjusting the number of frames we'll write to not exceed the array length.
const int32_t traces_length =
- soa.Decode<mirror::ObjectArray<mirror::StackTraceElement>*>(result)->GetLength();
+ soa.Decode<mirror::ObjectArray<mirror::StackTraceElement>>(result)->GetLength();
depth = std::min(depth, traces_length);
} else {
// Create java_trace array and place in local reference table
@@ -2153,7 +2156,7 @@
for (int32_t i = 0; i < depth; ++i) {
mirror::ObjectArray<mirror::Object>* decoded_traces =
- soa.Decode<mirror::Object*>(internal)->AsObjectArray<mirror::Object>();
+ soa.Decode<mirror::Object>(internal)->AsObjectArray<mirror::Object>();
// Methods and dex PC trace is element 0.
DCHECK(decoded_traces->Get(0)->IsIntArray() || decoded_traces->Get(0)->IsLongArray());
mirror::PointerArray* const method_trace =
@@ -2205,7 +2208,7 @@
return nullptr;
}
// We are called from native: use non-transactional mode.
- soa.Decode<mirror::ObjectArray<mirror::StackTraceElement>*>(result)->Set<false>(i, obj);
+ soa.Decode<mirror::ObjectArray<mirror::StackTraceElement>>(result)->Set<false>(i, obj);
}
return result;
}
@@ -3044,11 +3047,10 @@
interpreter::EnterInterpreterFromDeoptimize(this, shadow_frame, from_code, result);
}
-void Thread::SetException(mirror::Throwable* new_exception) {
+void Thread::SetException(ObjPtr<mirror::Throwable> new_exception) {
CHECK(new_exception != nullptr);
// TODO: DCHECK(!IsExceptionPending());
- tlsPtr_.exception = new_exception;
- // LOG(ERROR) << new_exception->Dump();
+ tlsPtr_.exception = new_exception.Decode();
}
} // namespace art
diff --git a/runtime/thread.h b/runtime/thread.h
index fb6bde6..f2c22d1 100644
--- a/runtime/thread.h
+++ b/runtime/thread.h
@@ -366,7 +366,7 @@
void AssertNoPendingException() const;
void AssertNoPendingExceptionForNewException(const char* msg) const;
- void SetException(mirror::Throwable* new_exception) REQUIRES_SHARED(Locks::mutator_lock_);
+ void SetException(ObjPtr<mirror::Throwable> new_exception) REQUIRES_SHARED(Locks::mutator_lock_);
void ClearException() REQUIRES_SHARED(Locks::mutator_lock_) {
tlsPtr_.exception = nullptr;
@@ -475,6 +475,8 @@
++poison_object_cookie_;
}
+ ALWAYS_INLINE static void PoisonObjectPointersIfDebug();
+
ALWAYS_INLINE uintptr_t GetPoisonObjectCookie() const {
return poison_object_cookie_;
}
@@ -900,7 +902,9 @@
// Returns the fake exception used to activate deoptimization.
static mirror::Throwable* GetDeoptimizationException() {
- return reinterpret_cast<mirror::Throwable*>(-1);
+ // Note that the mirror::Throwable must be aligned to kObjectAlignment or else it cannot be
+ // represented by ObjPtr.
+ return reinterpret_cast<mirror::Throwable*>(0x100);
}
// Currently deoptimization invokes verifier which can trigger class loading
diff --git a/runtime/thread_list.cc b/runtime/thread_list.cc
index 17c6c2e..e2aca6a 100644
--- a/runtime/thread_list.cc
+++ b/runtime/thread_list.cc
@@ -36,7 +36,7 @@
#include "lock_word.h"
#include "monitor.h"
#include "native_stack_dump.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
#include "thread.h"
#include "trace.h"
#include "well_known_classes.h"
diff --git a/runtime/trace.cc b/runtime/trace.cc
index 23591c2..f8467467 100644
--- a/runtime/trace.cc
+++ b/runtime/trace.cc
@@ -37,7 +37,7 @@
#include "mirror/object_array-inl.h"
#include "mirror/object-inl.h"
#include "os.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
#include "ScopedLocalRef.h"
#include "thread.h"
#include "thread_list.h"
diff --git a/runtime/transaction_test.cc b/runtime/transaction_test.cc
index 82e529c..77c2b76 100644
--- a/runtime/transaction_test.cc
+++ b/runtime/transaction_test.cc
@@ -22,7 +22,7 @@
#include "common_runtime_test.h"
#include "dex_file.h"
#include "mirror/array-inl.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
namespace art {
@@ -36,7 +36,7 @@
jobject jclass_loader = LoadDex("Transaction");
StackHandleScope<2> hs(soa.Self());
Handle<mirror::ClassLoader> class_loader(
- hs.NewHandle(soa.Decode<mirror::ClassLoader*>(jclass_loader)));
+ hs.NewHandle(soa.Decode<mirror::ClassLoader>(jclass_loader)));
ASSERT_TRUE(class_loader.Get() != nullptr);
// Load and initialize java.lang.ExceptionInInitializerError and the exception class used
@@ -173,7 +173,7 @@
ScopedObjectAccess soa(Thread::Current());
StackHandleScope<4> hs(soa.Self());
Handle<mirror::ClassLoader> class_loader(
- hs.NewHandle(soa.Decode<mirror::ClassLoader*>(LoadDex("Transaction"))));
+ hs.NewHandle(soa.Decode<mirror::ClassLoader>(LoadDex("Transaction"))));
ASSERT_TRUE(class_loader.Get() != nullptr);
Handle<mirror::Class> h_klass(
@@ -271,7 +271,7 @@
ScopedObjectAccess soa(Thread::Current());
StackHandleScope<5> hs(soa.Self());
Handle<mirror::ClassLoader> class_loader(
- hs.NewHandle(soa.Decode<mirror::ClassLoader*>(LoadDex("Transaction"))));
+ hs.NewHandle(soa.Decode<mirror::ClassLoader>(LoadDex("Transaction"))));
ASSERT_TRUE(class_loader.Get() != nullptr);
Handle<mirror::Class> h_klass(
@@ -373,7 +373,7 @@
ScopedObjectAccess soa(Thread::Current());
StackHandleScope<4> hs(soa.Self());
Handle<mirror::ClassLoader> class_loader(
- hs.NewHandle(soa.Decode<mirror::ClassLoader*>(LoadDex("Transaction"))));
+ hs.NewHandle(soa.Decode<mirror::ClassLoader>(LoadDex("Transaction"))));
ASSERT_TRUE(class_loader.Get() != nullptr);
Handle<mirror::Class> h_klass(
@@ -490,7 +490,7 @@
ScopedObjectAccess soa(Thread::Current());
StackHandleScope<3> hs(soa.Self());
Handle<mirror::ClassLoader> class_loader(
- hs.NewHandle(soa.Decode<mirror::ClassLoader*>(LoadDex("Transaction"))));
+ hs.NewHandle(soa.Decode<mirror::ClassLoader>(LoadDex("Transaction"))));
ASSERT_TRUE(class_loader.Get() != nullptr);
Handle<mirror::Class> h_klass(
@@ -539,7 +539,7 @@
ScopedObjectAccess soa(Thread::Current());
StackHandleScope<2> hs(soa.Self());
Handle<mirror::ClassLoader> class_loader(
- hs.NewHandle(soa.Decode<mirror::ClassLoader*>(LoadDex("Transaction"))));
+ hs.NewHandle(soa.Decode<mirror::ClassLoader>(LoadDex("Transaction"))));
ASSERT_TRUE(class_loader.Get() != nullptr);
Handle<mirror::Class> h_klass(
@@ -563,7 +563,7 @@
ScopedObjectAccess soa(Thread::Current());
StackHandleScope<2> hs(soa.Self());
Handle<mirror::ClassLoader> class_loader(
- hs.NewHandle(soa.Decode<mirror::ClassLoader*>(LoadDex("Transaction"))));
+ hs.NewHandle(soa.Decode<mirror::ClassLoader>(LoadDex("Transaction"))));
ASSERT_TRUE(class_loader.Get() != nullptr);
Handle<mirror::Class> h_klass(
diff --git a/runtime/type_lookup_table_test.cc b/runtime/type_lookup_table_test.cc
index ea4d8b5..ec38b41 100644
--- a/runtime/type_lookup_table_test.cc
+++ b/runtime/type_lookup_table_test.cc
@@ -19,7 +19,7 @@
#include "common_runtime_test.h"
#include "dex_file-inl.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
#include "type_lookup_table.h"
#include "utf-inl.h"
diff --git a/runtime/utils.cc b/runtime/utils.cc
index b52e2f2..a40e313 100644
--- a/runtime/utils.cc
+++ b/runtime/utils.cc
@@ -37,8 +37,9 @@
#include "mirror/object_array-inl.h"
#include "mirror/string.h"
#include "oat_quick_method_header.h"
+#include "obj_ptr-inl.h"
#include "os.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
#include "utf-inl.h"
#if defined(__APPLE__)
@@ -270,14 +271,14 @@
}
}
-std::string PrettyDescriptor(mirror::String* java_descriptor) {
+std::string PrettyStringDescriptor(ObjPtr<mirror::String> java_descriptor) {
if (java_descriptor == nullptr) {
return "null";
}
return PrettyDescriptor(java_descriptor->ToModifiedUtf8().c_str());
}
-std::string PrettyDescriptor(mirror::Class* klass) {
+std::string PrettyDescriptor(ObjPtr<mirror::Class> klass) {
if (klass == nullptr) {
return "null";
}
@@ -456,7 +457,7 @@
return result;
}
-std::string PrettyTypeOf(mirror::Object* obj) {
+std::string PrettyTypeOf(ObjPtr<mirror::Object> obj) {
if (obj == nullptr) {
return "null";
}
@@ -471,7 +472,7 @@
return result;
}
-std::string PrettyClass(mirror::Class* c) {
+std::string PrettyClass(ObjPtr<mirror::Class> c) {
if (c == nullptr) {
return "null";
}
@@ -482,7 +483,7 @@
return result;
}
-std::string PrettyClassAndClassLoader(mirror::Class* c) {
+std::string PrettyClassAndClassLoader(ObjPtr<mirror::Class> c) {
if (c == nullptr) {
return "null";
}
diff --git a/runtime/utils.h b/runtime/utils.h
index e65b947..ea9e8f7 100644
--- a/runtime/utils.h
+++ b/runtime/utils.h
@@ -33,6 +33,7 @@
#include "base/mutex.h"
#include "base/stringpiece.h"
#include "globals.h"
+#include "obj_ptr.h"
#include "primitive.h"
class BacktraceMap;
@@ -135,10 +136,10 @@
// Returns a human-readable equivalent of 'descriptor'. So "I" would be "int",
// "[[I" would be "int[][]", "[Ljava/lang/String;" would be
// "java.lang.String[]", and so forth.
-std::string PrettyDescriptor(mirror::String* descriptor)
+std::string PrettyStringDescriptor(ObjPtr<mirror::String> descriptor)
REQUIRES_SHARED(Locks::mutator_lock_);
std::string PrettyDescriptor(const char* descriptor);
-std::string PrettyDescriptor(mirror::Class* klass)
+std::string PrettyDescriptor(ObjPtr<mirror::Class> klass)
REQUIRES_SHARED(Locks::mutator_lock_);
std::string PrettyDescriptor(Primitive::Type type);
@@ -158,7 +159,7 @@
// So given an instance of java.lang.String, the output would
// be "java.lang.String". Given an array of int, the output would be "int[]".
// Given String.class, the output would be "java.lang.Class<java.lang.String>".
-std::string PrettyTypeOf(mirror::Object* obj)
+std::string PrettyTypeOf(ObjPtr<mirror::Object> obj)
REQUIRES_SHARED(Locks::mutator_lock_);
// Returns a human-readable form of the type at an index in the specified dex file.
@@ -167,11 +168,11 @@
// Returns a human-readable form of the name of the given class.
// Given String.class, the output would be "java.lang.Class<java.lang.String>".
-std::string PrettyClass(mirror::Class* c)
+std::string PrettyClass(ObjPtr<mirror::Class> c)
REQUIRES_SHARED(Locks::mutator_lock_);
// Returns a human-readable form of the name of the given class with its class loader.
-std::string PrettyClassAndClassLoader(mirror::Class* c)
+std::string PrettyClassAndClassLoader(ObjPtr<mirror::Class> c)
REQUIRES_SHARED(Locks::mutator_lock_);
// Returns a human-readable version of the Java part of the access flags, e.g., "private static "
diff --git a/runtime/utils_test.cc b/runtime/utils_test.cc
index 3ba20a4..ef42222 100644
--- a/runtime/utils_test.cc
+++ b/runtime/utils_test.cc
@@ -26,7 +26,7 @@
#include "mirror/object-inl.h"
#include "mirror/object_array-inl.h"
#include "mirror/string.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
#include "handle_scope-inl.h"
#include "base/memory_tool.h"
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index 13ef043..87b6dc3 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -46,7 +46,7 @@
#include "reg_type-inl.h"
#include "register_line-inl.h"
#include "runtime.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
#include "utils.h"
#include "verifier_deps.h"
#include "handle_scope-inl.h"
diff --git a/runtime/verifier/method_verifier_test.cc b/runtime/verifier/method_verifier_test.cc
index 646987a..837ee2d 100644
--- a/runtime/verifier/method_verifier_test.cc
+++ b/runtime/verifier/method_verifier_test.cc
@@ -22,7 +22,7 @@
#include "class_linker-inl.h"
#include "common_runtime_test.h"
#include "dex_file.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
#include "verifier_log_mode.h"
namespace art {
diff --git a/runtime/verifier/reg_type.cc b/runtime/verifier/reg_type.cc
index 3bc2acc..a84668b 100644
--- a/runtime/verifier/reg_type.cc
+++ b/runtime/verifier/reg_type.cc
@@ -27,7 +27,7 @@
#include "mirror/object-inl.h"
#include "mirror/object_array-inl.h"
#include "reg_type_cache-inl.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
#include <limits>
#include <sstream>
diff --git a/runtime/verifier/reg_type_test.cc b/runtime/verifier/reg_type_test.cc
index f2411b5..49dac26 100644
--- a/runtime/verifier/reg_type_test.cc
+++ b/runtime/verifier/reg_type_test.cc
@@ -24,7 +24,7 @@
#include "common_runtime_test.h"
#include "reg_type_cache-inl.h"
#include "reg_type-inl.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
#include "thread-inl.h"
namespace art {
diff --git a/runtime/verifier/verifier_deps_test.cc b/runtime/verifier/verifier_deps_test.cc
index bbaf59f..4533464 100644
--- a/runtime/verifier/verifier_deps_test.cc
+++ b/runtime/verifier/verifier_deps_test.cc
@@ -25,7 +25,7 @@
#include "mirror/class_loader.h"
#include "runtime.h"
#include "thread.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
namespace art {
namespace verifier {
@@ -58,7 +58,7 @@
REQUIRES_SHARED(Locks::mutator_lock_) {
StackHandleScope<1> hs(Thread::Current());
Handle<mirror::ClassLoader> class_loader_handle(
- hs.NewHandle(soa->Decode<mirror::ClassLoader*>(class_loader_)));
+ hs.NewHandle(soa->Decode<mirror::ClassLoader>(class_loader_)));
mirror::Class* klass = class_linker_->FindClass(Thread::Current(),
name.c_str(),
class_loader_handle);
@@ -84,8 +84,8 @@
SetVerifierDeps(dex_files);
- mirror::ClassLoader* loader = soa->Decode<mirror::ClassLoader*>(class_loader_);
- class_linker_->RegisterDexFile(*dex_file_, loader);
+ ObjPtr<mirror::ClassLoader> loader = soa->Decode<mirror::ClassLoader>(class_loader_);
+ class_linker_->RegisterDexFile(*dex_file_, loader.Decode());
klass_Main_ = FindClassByName("LMain;", soa);
CHECK(klass_Main_ != nullptr);
@@ -97,7 +97,7 @@
StackHandleScope<2> hs(Thread::Current());
Handle<mirror::ClassLoader> class_loader_handle(
- hs.NewHandle(soa.Decode<mirror::ClassLoader*>(class_loader_)));
+ hs.NewHandle(soa.Decode<mirror::ClassLoader>(class_loader_)));
Handle<mirror::DexCache> dex_cache_handle(hs.NewHandle(klass_Main_->GetDexCache()));
const DexFile::ClassDef* class_def = klass_Main_->GetClassDef();
diff --git a/runtime/well_known_classes.cc b/runtime/well_known_classes.cc
index e5216fb..4dcf58f 100644
--- a/runtime/well_known_classes.cc
+++ b/runtime/well_known_classes.cc
@@ -25,7 +25,7 @@
#include "mirror/class.h"
#include "mirror/throwable.h"
#include "ScopedLocalRef.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
#include "thread-inl.h"
namespace art {
diff --git a/test/004-ThreadStress/thread_stress.cc b/test/004-ThreadStress/thread_stress.cc
index 573c352..8ae3dfb 100644
--- a/test/004-ThreadStress/thread_stress.cc
+++ b/test/004-ThreadStress/thread_stress.cc
@@ -19,18 +19,18 @@
#include "jni.h"
#include "mirror/string.h"
#include "mirror/throwable.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
namespace art {
extern "C" JNIEXPORT void JNICALL Java_Main_printString(JNIEnv*, jclass, jstring s) {
ScopedObjectAccess soa(Thread::Current());
- std::cout << soa.Decode<mirror::String*>(s)->ToModifiedUtf8();
+ std::cout << soa.Decode<mirror::String>(s)->ToModifiedUtf8();
}
extern "C" JNIEXPORT void JNICALL Java_Main_printThrowable(JNIEnv*, jclass, jthrowable t) {
ScopedObjectAccess soa(Thread::Current());
- std::cout << soa.Decode<mirror::Throwable*>(t)->Dump();
+ std::cout << soa.Decode<mirror::Throwable>(t)->Dump();
}
} // namespace art
diff --git a/test/004-UnsafeTest/unsafe_test.cc b/test/004-UnsafeTest/unsafe_test.cc
index 3b0cf23..4f6ae5a 100644
--- a/test/004-UnsafeTest/unsafe_test.cc
+++ b/test/004-UnsafeTest/unsafe_test.cc
@@ -20,20 +20,20 @@
#include "mirror/class.h"
#include "mirror/class-inl.h"
#include "mirror/object-inl.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
namespace art {
extern "C" JNIEXPORT jint JNICALL Java_Main_vmArrayBaseOffset(JNIEnv* env, jclass, jobject classObj) {
ScopedObjectAccess soa(env);
- mirror::Class* klass = soa.Decode<mirror::Class*>(classObj);
+ ObjPtr<mirror::Class> klass = soa.Decode<mirror::Class>(classObj);
return mirror::Array::DataOffset(
Primitive::ComponentSize(klass->GetComponentType()->GetPrimitiveType())).Int32Value();
}
extern "C" JNIEXPORT jint JNICALL Java_Main_vmArrayIndexScale(JNIEnv* env, jclass, jobject classObj) {
ScopedObjectAccess soa(env);
- mirror::Class* klass = soa.Decode<mirror::Class*>(classObj);
+ ObjPtr<mirror::Class> klass = soa.Decode<mirror::Class>(classObj);
return Primitive::ComponentSize(klass->GetComponentType()->GetPrimitiveType());
}
diff --git a/test/054-uncaught/src/Main.java b/test/054-uncaught/src/Main.java
index 90a2311..688a2a4 100644
--- a/test/054-uncaught/src/Main.java
+++ b/test/054-uncaught/src/Main.java
@@ -41,7 +41,7 @@
ThreadDeathHandler defHandler = new ThreadDeathHandler("DEFAULT");
ThreadDeathHandler threadHandler = new ThreadDeathHandler("THREAD");
- System.out.println("Test " + which);
+ System.err.println("Test " + which);
switch (which) {
case 1: {
Thread.setDefaultUncaughtExceptionHandler(defHandler);
diff --git a/test/117-nopatchoat/nopatchoat.cc b/test/117-nopatchoat/nopatchoat.cc
index c6a2e9a..56c0dcd 100644
--- a/test/117-nopatchoat/nopatchoat.cc
+++ b/test/117-nopatchoat/nopatchoat.cc
@@ -20,7 +20,7 @@
#include "gc/space/image_space.h"
#include "mirror/class-inl.h"
#include "runtime.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
#include "thread.h"
namespace art {
@@ -29,7 +29,7 @@
public:
static const OatFile::OatDexFile* getOatDexFile(jclass cls) {
ScopedObjectAccess soa(Thread::Current());
- mirror::Class* klass = soa.Decode<mirror::Class*>(cls);
+ ObjPtr<mirror::Class> klass = soa.Decode<mirror::Class>(cls);
const DexFile& dex_file = klass->GetDexFile();
return dex_file.GetOatDexFile();
}
diff --git a/test/1337-gc-coverage/gc_coverage.cc b/test/1337-gc-coverage/gc_coverage.cc
index 7cf30bd..1e60bd9 100644
--- a/test/1337-gc-coverage/gc_coverage.cc
+++ b/test/1337-gc-coverage/gc_coverage.cc
@@ -17,7 +17,7 @@
#include "gc/heap.h"
#include "jni.h"
#include "runtime.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
#include "thread-inl.h"
namespace art {
@@ -43,7 +43,7 @@
extern "C" JNIEXPORT jlong JNICALL Java_Main_objectAddress(JNIEnv* env, jclass, jobject object) {
ScopedObjectAccess soa(env);
- return reinterpret_cast<jlong>(soa.Decode<mirror::Object*>(object));
+ return reinterpret_cast<jlong>(soa.Decode<mirror::Object>(object).Decode());
}
extern "C" JNIEXPORT jboolean JNICALL Java_Main_supportCollectorTransition(JNIEnv*, jclass) {
diff --git a/test/148-multithread-gc-annotations/gc_coverage.cc b/test/148-multithread-gc-annotations/gc_coverage.cc
index 263eefd..cb12df4 100644
--- a/test/148-multithread-gc-annotations/gc_coverage.cc
+++ b/test/148-multithread-gc-annotations/gc_coverage.cc
@@ -17,7 +17,7 @@
#include "gc/heap.h"
#include "jni.h"
#include "runtime.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
#include "thread-inl.h"
namespace art {
@@ -35,7 +35,7 @@
extern "C" JNIEXPORT jlong JNICALL Java_MovingGCThread_objectAddress(JNIEnv* env, jclass, jobject object) {
ScopedObjectAccess soa(env);
- return reinterpret_cast<jlong>(soa.Decode<mirror::Object*>(object));
+ return reinterpret_cast<jlong>(soa.Decode<mirror::Object>(object).Decode());
}
} // namespace
diff --git a/test/454-get-vreg/get_vreg_jni.cc b/test/454-get-vreg/get_vreg_jni.cc
index 5762754..9058af4 100644
--- a/test/454-get-vreg/get_vreg_jni.cc
+++ b/test/454-get-vreg/get_vreg_jni.cc
@@ -18,7 +18,7 @@
#include "art_method-inl.h"
#include "jni.h"
#include "oat_quick_method_header.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
#include "stack.h"
#include "thread.h"
@@ -123,7 +123,7 @@
extern "C" JNIEXPORT jint JNICALL Java_Main_doNativeCall(JNIEnv*, jobject value) {
ScopedObjectAccess soa(Thread::Current());
std::unique_ptr<Context> context(Context::Create());
- TestVisitor visitor(soa.Self(), context.get(), soa.Decode<mirror::Object*>(value));
+ TestVisitor visitor(soa.Self(), context.get(), soa.Decode<mirror::Object>(value).Decode());
visitor.WalkStack();
return visitor.found_method_index_;
}
diff --git a/test/457-regs/regs_jni.cc b/test/457-regs/regs_jni.cc
index 08db775..f62a77d 100644
--- a/test/457-regs/regs_jni.cc
+++ b/test/457-regs/regs_jni.cc
@@ -18,7 +18,7 @@
#include "art_method-inl.h"
#include "jni.h"
#include "oat_quick_method_header.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
#include "stack.h"
#include "thread.h"
@@ -139,7 +139,7 @@
JNIEnv*, jclass value ATTRIBUTE_UNUSED, jobject main, jint int_value, jfloat float_value) {
ScopedObjectAccess soa(Thread::Current());
std::unique_ptr<Context> context(Context::Create());
- CHECK(soa.Decode<mirror::Object*>(main) == nullptr);
+ CHECK(soa.Decode<mirror::Object>(main) == nullptr);
CHECK_EQ(int_value, 0);
int32_t cast = bit_cast<int32_t, float>(float_value);
CHECK_EQ(cast, 0);
diff --git a/test/461-get-reference-vreg/get_reference_vreg_jni.cc b/test/461-get-reference-vreg/get_reference_vreg_jni.cc
index 8122c6d..7b1ab9c 100644
--- a/test/461-get-reference-vreg/get_reference_vreg_jni.cc
+++ b/test/461-get-reference-vreg/get_reference_vreg_jni.cc
@@ -17,7 +17,7 @@
#include "arch/context.h"
#include "art_method-inl.h"
#include "jni.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
#include "stack.h"
#include "thread.h"
@@ -70,7 +70,7 @@
extern "C" JNIEXPORT jint JNICALL Java_Main_doNativeCallRef(JNIEnv*, jobject value) {
ScopedObjectAccess soa(Thread::Current());
std::unique_ptr<Context> context(Context::Create());
- TestVisitor visitor(soa.Self(), context.get(), soa.Decode<mirror::Object*>(value));
+ TestVisitor visitor(soa.Self(), context.get(), soa.Decode<mirror::Object>(value).Decode());
visitor.WalkStack();
return visitor.found_method_index_;
}
diff --git a/test/466-get-live-vreg/get_live_vreg_jni.cc b/test/466-get-live-vreg/get_live_vreg_jni.cc
index 3618b4f..d3a033b 100644
--- a/test/466-get-live-vreg/get_live_vreg_jni.cc
+++ b/test/466-get-live-vreg/get_live_vreg_jni.cc
@@ -18,7 +18,7 @@
#include "art_method-inl.h"
#include "jni.h"
#include "oat_quick_method_header.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
#include "stack.h"
#include "thread.h"
diff --git a/test/497-inlining-and-class-loader/clear_dex_cache.cc b/test/497-inlining-and-class-loader/clear_dex_cache.cc
index 1597c4a..3f2df29 100644
--- a/test/497-inlining-and-class-loader/clear_dex_cache.cc
+++ b/test/497-inlining-and-class-loader/clear_dex_cache.cc
@@ -17,7 +17,7 @@
#include "art_method-inl.h"
#include "base/enums.h"
#include "jni.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
#include "stack.h"
#include "thread.h"
@@ -29,7 +29,7 @@
jclass,
jclass cls) {
ScopedObjectAccess soa(Thread::Current());
- mirror::DexCache* dex_cache = soa.Decode<mirror::Class*>(cls)->GetDexCache();
+ mirror::DexCache* dex_cache = soa.Decode<mirror::Class>(cls)->GetDexCache();
size_t num_methods = dex_cache->NumResolvedMethods();
ArtMethod** methods = dex_cache->GetResolvedMethods();
CHECK_EQ(num_methods != 0u, methods != nullptr);
@@ -43,7 +43,7 @@
array = env->NewLongArray(num_methods);
}
CHECK(array != nullptr);
- mirror::PointerArray* pointer_array = soa.Decode<mirror::PointerArray*>(array);
+ mirror::PointerArray* pointer_array = soa.Decode<mirror::PointerArray>(array).Decode();
for (size_t i = 0; i != num_methods; ++i) {
ArtMethod* method = mirror::DexCache::GetElementPtrSize(methods, i, kRuntimePointerSize);
pointer_array->SetElementPtrSize(i, method, kRuntimePointerSize);
@@ -54,11 +54,11 @@
extern "C" JNIEXPORT void JNICALL Java_Main_restoreResolvedMethods(
JNIEnv*, jclass, jclass cls, jobject old_cache) {
ScopedObjectAccess soa(Thread::Current());
- mirror::DexCache* dex_cache = soa.Decode<mirror::Class*>(cls)->GetDexCache();
+ mirror::DexCache* dex_cache = soa.Decode<mirror::Class>(cls)->GetDexCache();
size_t num_methods = dex_cache->NumResolvedMethods();
- ArtMethod** methods = soa.Decode<mirror::Class*>(cls)->GetDexCache()->GetResolvedMethods();
+ ArtMethod** methods = soa.Decode<mirror::Class>(cls)->GetDexCache()->GetResolvedMethods();
CHECK_EQ(num_methods != 0u, methods != nullptr);
- mirror::PointerArray* old = soa.Decode<mirror::PointerArray*>(old_cache);
+ ObjPtr<mirror::PointerArray> old = soa.Decode<mirror::PointerArray>(old_cache);
CHECK_EQ(methods != nullptr, old != nullptr);
CHECK_EQ(num_methods, static_cast<size_t>(old->GetLength()));
for (size_t i = 0; i != num_methods; ++i) {
diff --git a/test/543-env-long-ref/env_long_ref.cc b/test/543-env-long-ref/env_long_ref.cc
index 557def6..cd127ef 100644
--- a/test/543-env-long-ref/env_long_ref.cc
+++ b/test/543-env-long-ref/env_long_ref.cc
@@ -17,7 +17,7 @@
#include "arch/context.h"
#include "art_method-inl.h"
#include "jni.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
#include "stack.h"
#include "thread.h"
@@ -43,7 +43,7 @@
uint32_t value = 0;
CHECK(GetVReg(m, 1, kReferenceVReg, &value));
CHECK_EQ(reinterpret_cast<mirror::Object*>(value),
- soa_.Decode<mirror::Object*>(expected_value_));
+ soa_.Decode<mirror::Object>(expected_value_).Decode());
}
return true;
}
diff --git a/test/566-polymorphic-inlining/polymorphic_inline.cc b/test/566-polymorphic-inlining/polymorphic_inline.cc
index 89293cc..00c1b02 100644
--- a/test/566-polymorphic-inlining/polymorphic_inline.cc
+++ b/test/566-polymorphic-inlining/polymorphic_inline.cc
@@ -20,14 +20,14 @@
#include "jit/jit_code_cache.h"
#include "jit/profiling_info.h"
#include "oat_quick_method_header.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
#include "stack_map.h"
namespace art {
static void do_checks(jclass cls, const char* method_name) {
ScopedObjectAccess soa(Thread::Current());
- mirror::Class* klass = soa.Decode<mirror::Class*>(cls);
+ ObjPtr<mirror::Class> klass = soa.Decode<mirror::Class>(cls);
jit::Jit* jit = Runtime::Current()->GetJit();
jit::JitCodeCache* code_cache = jit->GetCodeCache();
ArtMethod* method = klass->FindDeclaredDirectMethodByName(method_name, kRuntimePointerSize);
@@ -53,7 +53,7 @@
static void allocate_profiling_info(jclass cls, const char* method_name) {
ScopedObjectAccess soa(Thread::Current());
- mirror::Class* klass = soa.Decode<mirror::Class*>(cls);
+ ObjPtr<mirror::Class> klass = soa.Decode<mirror::Class>(cls);
ArtMethod* method = klass->FindDeclaredDirectMethodByName(method_name, kRuntimePointerSize);
ProfilingInfo::Create(soa.Self(), method, /* retry_allocation */ true);
}
diff --git a/test/570-checker-osr/osr.cc b/test/570-checker-osr/osr.cc
index adda3cc..50e8382 100644
--- a/test/570-checker-osr/osr.cc
+++ b/test/570-checker-osr/osr.cc
@@ -19,7 +19,7 @@
#include "jit/jit_code_cache.h"
#include "jit/profiling_info.h"
#include "oat_quick_method_header.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
#include "ScopedUtfChars.h"
#include "stack_map.h"
diff --git a/test/595-profile-saving/profile-saving.cc b/test/595-profile-saving/profile-saving.cc
index a265dce..bf3d812 100644
--- a/test/595-profile-saving/profile-saving.cc
+++ b/test/595-profile-saving/profile-saving.cc
@@ -24,7 +24,7 @@
#include "mirror/class-inl.h"
#include "oat_file_assistant.h"
#include "oat_file_manager.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
#include "ScopedUtfChars.h"
#include "thread.h"
@@ -74,7 +74,7 @@
ScopedUtfChars filename_chars(env, filename);
CHECK(filename_chars.c_str() != nullptr);
ScopedObjectAccess soa(Thread::Current());
- const DexFile* dex_file = soa.Decode<mirror::Class*>(cls)->GetDexCache()->GetDexFile();
+ const DexFile* dex_file = soa.Decode<mirror::Class>(cls)->GetDexCache()->GetDexFile();
return ProfileSaver::HasSeenMethod(std::string(filename_chars.c_str()),
dex_file,
static_cast<uint16_t>(method_index));
diff --git a/test/596-app-images/app_images.cc b/test/596-app-images/app_images.cc
index a5bbf5f..78cc3fd 100644
--- a/test/596-app-images/app_images.cc
+++ b/test/596-app-images/app_images.cc
@@ -26,7 +26,7 @@
#include "jni.h"
#include "mirror/class.h"
#include "runtime.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
namespace art {
@@ -48,13 +48,13 @@
extern "C" JNIEXPORT jboolean JNICALL Java_Main_checkAppImageContains(JNIEnv*, jclass, jclass c) {
ScopedObjectAccess soa(Thread::Current());
- mirror::Class* klass_ptr = soa.Decode<mirror::Class*>(c);
+ ObjPtr<mirror::Class> klass_ptr = soa.Decode<mirror::Class>(c);
for (auto* space : Runtime::Current()->GetHeap()->GetContinuousSpaces()) {
if (space->IsImageSpace()) {
auto* image_space = space->AsImageSpace();
const auto& image_header = image_space->GetImageHeader();
if (image_header.IsAppImage()) {
- if (image_space->HasAddress(klass_ptr)) {
+ if (image_space->HasAddress(klass_ptr.Decode())) {
return JNI_TRUE;
}
}
diff --git a/test/Android.bp b/test/Android.bp
index 72dcbba..628f377 100644
--- a/test/Android.bp
+++ b/test/Android.bp
@@ -110,7 +110,7 @@
"-Wl,-u,Java_MyClassNatives_sbar",
],
shared_libs: [
- "libcutils",
+ "liblog",
"libdl",
"libz",
],
diff --git a/test/common/runtime_state.cc b/test/common/runtime_state.cc
index fd1ba02..4248148 100644
--- a/test/common/runtime_state.cc
+++ b/test/common/runtime_state.cc
@@ -24,7 +24,7 @@
#include "mirror/class-inl.h"
#include "oat_quick_method_header.h"
#include "runtime.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
#include "ScopedUtfChars.h"
#include "thread-inl.h"
@@ -35,7 +35,7 @@
extern "C" JNIEXPORT jboolean JNICALL Java_Main_hasOatFile(JNIEnv* env, jclass cls) {
ScopedObjectAccess soa(env);
- mirror::Class* klass = soa.Decode<mirror::Class*>(cls);
+ ObjPtr<mirror::Class> klass = soa.Decode<mirror::Class>(cls);
const DexFile& dex_file = klass->GetDexFile();
const OatFile::OatDexFile* oat_dex_file = dex_file.GetOatDexFile();
return (oat_dex_file != nullptr) ? JNI_TRUE : JNI_FALSE;
@@ -75,7 +75,7 @@
extern "C" JNIEXPORT jboolean JNICALL Java_Main_compiledWithOptimizing(JNIEnv* env, jclass cls) {
ScopedObjectAccess soa(env);
- mirror::Class* klass = soa.Decode<mirror::Class*>(cls);
+ ObjPtr<mirror::Class> klass = soa.Decode<mirror::Class>(cls);
const DexFile& dex_file = klass->GetDexFile();
const OatFile::OatDexFile* oat_dex_file = dex_file.GetOatDexFile();
if (oat_dex_file == nullptr) {
@@ -134,7 +134,7 @@
ScopedUtfChars chars(env, method_name);
CHECK(chars.c_str() != nullptr);
- method = soa.Decode<mirror::Class*>(cls)->FindDeclaredDirectMethodByName(
+ method = soa.Decode<mirror::Class>(cls)->FindDeclaredDirectMethodByName(
chars.c_str(), kRuntimePointerSize);
}
diff --git a/test/common/stack_inspect.cc b/test/common/stack_inspect.cc
index 85ea1c8..d2aacf0 100644
--- a/test/common/stack_inspect.cc
+++ b/test/common/stack_inspect.cc
@@ -21,7 +21,7 @@
#include "mirror/class-inl.h"
#include "nth_caller_visitor.h"
#include "runtime.h"
-#include "scoped_thread_state_change.h"
+#include "scoped_thread_state_change-inl.h"
#include "stack.h"
#include "thread-inl.h"
@@ -62,7 +62,7 @@
static jboolean IsManaged(JNIEnv* env, jclass cls, size_t level) {
ScopedObjectAccess soa(env);
- mirror::Class* klass = soa.Decode<mirror::Class*>(cls);
+ ObjPtr<mirror::Class> klass = soa.Decode<mirror::Class>(cls);
const DexFile& dex_file = klass->GetDexFile();
const OatFile::OatDexFile* oat_dex_file = dex_file.GetOatDexFile();
if (oat_dex_file == nullptr) {
diff --git a/test/etc/run-test-jar b/test/etc/run-test-jar
index c51cb0d..d8f42a2 100755
--- a/test/etc/run-test-jar
+++ b/test/etc/run-test-jar
@@ -404,6 +404,24 @@
fi
fi
+# Prevent test from silently falling back to interpreter in no-prebuild mode. This happens
+# when DEX_LOCATION path is too long, because vdex/odex filename is constructed by taking
+# full path to dex, stripping leading '/', appending '@classes.vdex' and changing every
+# remaining '/' into '@'.
+if [ "$HOST" = "y" ]; then
+ max_filename_size=$(getconf NAME_MAX $DEX_LOCATION)
+else
+ # There is no getconf on device, fallback to standard value. See NAME_MAX in kernel <linux/limits.h>
+ max_filename_size=255
+fi
+# Compute VDEX_NAME.
+DEX_LOCATION_STRIPPED="${DEX_LOCATION#/}"
+VDEX_NAME="${DEX_LOCATION_STRIPPED//\//@}@$TEST_NAME.jar@classes.vdex"
+if [ ${#VDEX_NAME} -gt $max_filename_size ]; then
+ echo "Dex location path too long."
+ exit 1
+fi
+
dex2oat_cmdline="true"
mkdir_locations="${DEX_LOCATION}/dalvik-cache/$ISA"
strip_cmdline="true"
diff --git a/tools/jfuzz/run_jfuzz_test.py b/tools/jfuzz/run_jfuzz_test.py
index 54f9bb4..fd8415d 100755
--- a/tools/jfuzz/run_jfuzz_test.py
+++ b/tools/jfuzz/run_jfuzz_test.py
@@ -450,13 +450,13 @@
os.mkdir(ddir)
for f in glob('*.txt') + ['Test.java']:
shutil.copy(f, ddir)
- # Maybe run bisection bug search.
- if (retc1 in BISECTABLE_RET_CODES and retc2 in BISECTABLE_RET_CODES and
- not (self._true_divergence_only and RetCode.TIMEOUT in (retc1, retc2))):
- self.MaybeBisectDivergence(retc1, retc2, is_output_divergence)
- # Call reporting script.
- if self._report_script:
- self.RunReportScript(retc1, retc2, is_output_divergence)
+ if not (self._true_divergence_only and RetCode.TIMEOUT in (retc1, retc2)):
+ # Maybe run bisection bug search.
+ if retc1 in BISECTABLE_RET_CODES and retc2 in BISECTABLE_RET_CODES:
+ self.MaybeBisectDivergence(retc1, retc2, is_output_divergence)
+ # Call reporting script.
+ if self._report_script:
+ self.RunReportScript(retc1, retc2, is_output_divergence)
def RunReportScript(self, retc1, retc2, is_output_divergence):
"""Runs report script."""
diff --git a/tools/jfuzz/run_jfuzz_test_nightly.py b/tools/jfuzz/run_jfuzz_test_nightly.py
index cd338fb..29595f2 100755
--- a/tools/jfuzz/run_jfuzz_test_nightly.py
+++ b/tools/jfuzz/run_jfuzz_test_nightly.py
@@ -16,9 +16,14 @@
import argparse
import os
+import re
+import shutil
import subprocess
import sys
+from glob import glob
+
+from tempfile import mkdtemp
from tempfile import TemporaryFile
# Default arguments for run_jfuzz_test.py.
@@ -51,15 +56,29 @@
for proc in processes:
proc.kill()
# Output results.
+ output_dirs = []
for i, output_file in enumerate(output_files):
output_file.seek(0)
output_str = output_file.read().decode('ascii')
output_file.close()
+ # Extract output directory. Example match: 'Directory : /tmp/tmp8ltpfjng'.
+ directory_match = re.search(r'Directory[^:]*: ([^\n]+)\n', output_str)
+ if directory_match:
+ output_dirs.append(directory_match.group(1))
print('Tester', i)
if output_str.find(SUCCESS_STRING) == NOT_FOUND:
print(output_str)
else:
print(SUCCESS_STRING)
+ # Gather divergences.
+ global_out_dir = mkdtemp('jfuzz_nightly')
+ divergence_nr = 1
+ for out_dir in output_dirs:
+ for divergence_dir in glob(out_dir + '/divergence*/'):
+ shutil.copytree(divergence_dir,
+ global_out_dir + '/divergence' + str(divergence_nr))
+ divergence_nr += 1
+ print('Global output directory:', global_out_dir)
if __name__ == '__main__':
main(sys.argv)