summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Vladimir Marko <vmarko@google.com> 2018-01-22 16:32:29 +0000
committer Vladimir Marko <vmarko@google.com> 2018-01-23 17:43:15 +0000
commit718e8319c728e9ee2ec15b1d56ca96baa4393028 (patch)
tree179d05bf61f23b02001da80df30cbd89fd5b5903
parentbe2b613f5a30cdf2291b9f4f5d0acc2c1bb0b4ae (diff)
ART: Use the bitstring type check for AOT app compilation.
For boot image target classes that have their bitstring already assigned in the boot image. The size of the services.odex for aosp_taimen-userdebug: - before: - arm64: 20988640 - after: - arm64: 20968016 (-20KiB, -0.1%) (There is no arm version, only arm64.) Test: New test case in 552-checker-sharpening. Test: m test-art-host-gtest Test: testrunner.py --host --optimizing Test: Pixel 2 XL boots. Test: testrunner.py --target --optimizing Bug: 64692057 Change-Id: I9585efca8ba0df15400e7536e5e2cc76aca13e8d
-rw-r--r--compiler/driver/compiler_driver.cc45
-rw-r--r--compiler/driver/compiler_driver.h11
-rw-r--r--compiler/optimizing/sharpening.cc6
-rw-r--r--runtime/entrypoints/quick/quick_throw_entrypoints.cc8
-rw-r--r--test/552-checker-sharpening/src/Main.java21
5 files changed, 88 insertions, 3 deletions
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index 70cbb01569..273bd50b9e 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -872,6 +872,14 @@ void CompilerDriver::PreCompile(jobject class_loader,
TimingLogger* timings) {
CheckThreadPools();
+ if (kUseBitstringTypeCheck &&
+ !compiler_options_->IsBootImage() &&
+ compiler_options_->IsAotCompilationEnabled()) {
+ RecordBootImageClassesWithAssignedBitstring();
+ VLOG(compiler) << "RecordBootImageClassesWithAssignedBitstring: "
+ << GetMemoryUsageString(false);
+ }
+
LoadImageClasses(timings);
VLOG(compiler) << "LoadImageClasses: " << GetMemoryUsageString(false);
@@ -940,6 +948,43 @@ void CompilerDriver::PreCompile(jobject class_loader,
}
}
+void CompilerDriver::RecordBootImageClassesWithAssignedBitstring() {
+ if (boot_image_classes_with_assigned_bitstring_ != nullptr) {
+ return; // Already recorded. (Happens because of class unloading between dex files.)
+ }
+
+ class Visitor : public ClassVisitor {
+ public:
+ explicit Visitor(std::unordered_set<mirror::Class*>* recorded_classes)
+ : recorded_classes_(recorded_classes) {}
+
+ bool operator()(ObjPtr<mirror::Class> klass) OVERRIDE
+ REQUIRES(Locks::subtype_check_lock_) REQUIRES_SHARED(Locks::mutator_lock_) {
+ DCHECK(klass != nullptr);
+ SubtypeCheckInfo::State state = SubtypeCheck<ObjPtr<mirror::Class>>::GetState(klass);
+ if (state == SubtypeCheckInfo::kAssigned) {
+ recorded_classes_->insert(klass.Ptr());
+ }
+ return true;
+ }
+
+ private:
+ std::unordered_set<mirror::Class*>* const recorded_classes_;
+ };
+
+ boot_image_classes_with_assigned_bitstring_.reset(new std::unordered_set<mirror::Class*>());
+ Visitor visitor(boot_image_classes_with_assigned_bitstring_.get());
+ ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+ ScopedObjectAccess soa(Thread::Current());
+ MutexLock subtype_check_lock(soa.Self(), *Locks::subtype_check_lock_);
+ class_linker->VisitClasses(&visitor);
+}
+
+bool CompilerDriver::IsBootImageClassWithAssignedBitstring(ObjPtr<mirror::Class> klass) {
+ DCHECK(boot_image_classes_with_assigned_bitstring_ != nullptr);
+ return boot_image_classes_with_assigned_bitstring_->count(klass.Ptr()) != 0u;
+}
+
bool CompilerDriver::IsImageClass(const char* descriptor) const {
if (image_classes_ != nullptr) {
// If we have a set of image classes, use those.
diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h
index 4b5916d572..30042751b3 100644
--- a/compiler/driver/compiler_driver.h
+++ b/compiler/driver/compiler_driver.h
@@ -385,12 +385,17 @@ class CompilerDriver {
return dex_to_dex_compiler_;
}
+ bool IsBootImageClassWithAssignedBitstring(ObjPtr<mirror::Class> klass)
+ REQUIRES_SHARED(Locks::mutator_lock_);
+
private:
void PreCompile(jobject class_loader,
const std::vector<const DexFile*>& dex_files,
TimingLogger* timings)
REQUIRES(!Locks::mutator_lock_);
+ void RecordBootImageClassesWithAssignedBitstring() REQUIRES(!Locks::mutator_lock_);
+
void LoadImageClasses(TimingLogger* timings) REQUIRES(!Locks::mutator_lock_);
// Attempt to resolve all type, methods, fields, and strings
@@ -513,6 +518,12 @@ class CompilerDriver {
// This option may be restricted to the boot image, depending on a flag in the implementation.
std::unique_ptr<std::unordered_set<std::string>> methods_to_compile_;
+ // For AOT app compilation, we keep the set of boot image classes with assigned type check
+ // bitstring. We need to retrieve this set before we initialize app image classes as the
+ // initialization can cause more boot image bitstrings to be assigned.
+ // Note that boot image classes are non-moveable, so it's OK to keep raw pointers.
+ std::unique_ptr<std::unordered_set<mirror::Class*>> boot_image_classes_with_assigned_bitstring_;
+
std::atomic<uint32_t> number_of_soft_verifier_failures_;
bool had_hard_verifier_failure_;
diff --git a/compiler/optimizing/sharpening.cc b/compiler/optimizing/sharpening.cc
index dffef17587..12319df2e8 100644
--- a/compiler/optimizing/sharpening.cc
+++ b/compiler/optimizing/sharpening.cc
@@ -253,9 +253,9 @@ static inline bool CanUseTypeCheckBitstring(ObjPtr<mirror::Class> klass,
// If the target is a boot image class, try to assign a type check bitstring (fall through).
// (If --force-determinism, this was already done; repeating is OK and yields the same result.)
} else {
- // TODO: Use the bitstring also for AOT app compilation if the target class has a bitstring
- // already assigned in the boot image.
- return false;
+ // For AOT app compilation we can use the bitstring iff the target class is
+ // a boot image class with a bitstring already assigned in the boot image.
+ return compiler_driver->IsBootImageClassWithAssignedBitstring(klass);
}
// Try to assign a type check bitstring.
diff --git a/runtime/entrypoints/quick/quick_throw_entrypoints.cc b/runtime/entrypoints/quick/quick_throw_entrypoints.cc
index 4b26beece3..db4891ebd8 100644
--- a/runtime/entrypoints/quick/quick_throw_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_throw_entrypoints.cc
@@ -126,6 +126,14 @@ extern "C" NO_RETURN void artThrowClassCastException(mirror::Class* dest_type,
dex::TypeIndex type_index(check_cast.VRegB_21c());
ClassLinker* linker = Runtime::Current()->GetClassLinker();
dest_type = linker->LookupResolvedType(type_index, visitor.caller).Ptr();
+ if (UNLIKELY(dest_type == nullptr)) {
+ // This class must have been resolved to the boot image at AOT compile time
+ // but it's not yet resolved in the app's class loader. Just look it up in
+ // the boot class path loader.
+ DCHECK(visitor.caller->GetClassLoader() != nullptr);
+ dest_type = linker->LookupResolvedType(
+ type_index, visitor.caller->GetDexCache(), /* class_loader */ nullptr).Ptr();
+ }
CHECK(dest_type != nullptr) << "Target class should have been previously resolved: "
<< visitor.caller->GetDexFile()->PrettyType(type_index);
}
diff --git a/test/552-checker-sharpening/src/Main.java b/test/552-checker-sharpening/src/Main.java
index 3173afdfcd..0623a22d64 100644
--- a/test/552-checker-sharpening/src/Main.java
+++ b/test/552-checker-sharpening/src/Main.java
@@ -14,8 +14,17 @@
* limitations under the License.
*/
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+
public class Main {
+ public static void assertBooleanEquals(boolean expected, boolean result) {
+ if (expected != result) {
+ throw new Error("Expected: " + expected + ", found: " + result);
+ }
+ }
+
public static void assertIntEquals(int expected, int result) {
if (expected != result) {
throw new Error("Expected: " + expected + ", found: " + result);
@@ -195,6 +204,14 @@ public class Main {
return Other.class;
}
+ /// CHECK-START: boolean Main.$noinline$instanceOfInputStream(java.lang.Object) builder (after)
+ /// CHECK-NOT: LoadClass
+ /// CHECK: InstanceOf check_kind:bitstring_check
+ public static boolean $noinline$instanceOfInputStream(Object o) {
+ // InputStream is known to be in the core image with an initialized type check bitstring.
+ return o instanceof InputStream;
+ }
+
public static void main(String[] args) {
assertIntEquals(1, testSimple(1));
assertIntEquals(1, testDiamond(false, 1));
@@ -208,6 +225,10 @@ public class Main {
assertStringEquals("non-boot-image-string", $noinline$getNonBootImageString());
assertClassEquals(String.class, $noinline$getStringClass());
assertClassEquals(Other.class, $noinline$getOtherClass());
+ assertBooleanEquals(false, $noinline$instanceOfInputStream(null));
+ assertBooleanEquals(false, $noinline$instanceOfInputStream(new Integer(1)));
+ assertBooleanEquals(true,
+ $noinline$instanceOfInputStream(new ByteArrayInputStream(new byte[10])));
}
}