summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Eric Holk <eholk@google.com> 2020-04-20 08:47:13 -0700
committer Treehugger Robot <treehugger-gerrit@google.com> 2020-04-27 22:31:29 +0000
commit7c25b09f62eb87b72bd8a98a31ea10fd97050f82 (patch)
treeb7a933b717ecee9a3243ec85bc176e05d16a1a60
parenta698102d622e1cff97a30428878c8075059f396c (diff)
Reject OAT file in speed-profile if app image is rejected
Speed profile should always have an app image available. This change makes ART refuse to load OAT files compiled with the speed-profile compiler filter if the app image cannot be loaded. This will enable the compiler to assume the existence of an app image and generate better code in some cases. Bug: 38313278 Test: ./test/run-test --host 2231-oat-require-app-image Change-Id: I2ee6fa7c7dc1d42d1fe1511fc60a7c0542237bfa
-rw-r--r--runtime/gc/heap.cc12
-rw-r--r--runtime/gc/heap.h1
-rw-r--r--runtime/oat_file.h7
-rw-r--r--runtime/oat_file_assistant_test.cc4
-rw-r--r--runtime/oat_file_manager.cc31
-rw-r--r--test/2231-oat-require-app-image/expected.txt2
-rw-r--r--test/2231-oat-require-app-image/info.txt1
-rw-r--r--test/2231-oat-require-app-image/profile1
-rw-r--r--test/2231-oat-require-app-image/run18
-rw-r--r--test/2231-oat-require-app-image/src/Main.java31
-rw-r--r--test/common/runtime_state.cc8
11 files changed, 101 insertions, 15 deletions
diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc
index b919cdda60..401394af6e 100644
--- a/runtime/gc/heap.cc
+++ b/runtime/gc/heap.cc
@@ -870,6 +870,18 @@ bool Heap::IsCompilingBoot() const {
return true;
}
+bool Heap::HasAppImageSpace() const {
+ for (const auto& space : GetContinuousSpaces()) {
+ if (space->IsImageSpace()) {
+ const gc::space::ImageSpace* image_space = space->AsImageSpace();
+ if (image_space->GetImageHeader().IsAppImage()) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
void Heap::IncrementDisableMovingGC(Thread* self) {
// Need to do this holding the lock to prevent races where the GC is about to run / running when
// we attempt to disable it.
diff --git a/runtime/gc/heap.h b/runtime/gc/heap.h
index 515dcb3a6d..9008c01a2b 100644
--- a/runtime/gc/heap.h
+++ b/runtime/gc/heap.h
@@ -783,6 +783,7 @@ class Heap {
bool HasBootImageSpace() const {
return !boot_image_spaces_.empty();
}
+ bool HasAppImageSpace() const REQUIRES_SHARED(Locks::mutator_lock_);
ReferenceProcessor* GetReferenceProcessor() {
return reference_processor_.get();
diff --git a/runtime/oat_file.h b/runtime/oat_file.h
index dce34d9728..75770d73f9 100644
--- a/runtime/oat_file.h
+++ b/runtime/oat_file.h
@@ -378,6 +378,13 @@ class OatFile {
return external_dex_files_.empty();
}
+ // Returns whether an image (e.g. app image) is required to safely execute this OAT file.
+ inline bool RequiresImage() const {
+ // We currently require images only for speed profile and everything profile.
+ return GetCompilerFilter() == CompilerFilter::Filter::kSpeedProfile ||
+ GetCompilerFilter() == CompilerFilter::Filter::kEverythingProfile;
+ }
+
protected:
OatFile(const std::string& filename, bool executable);
diff --git a/runtime/oat_file_assistant_test.cc b/runtime/oat_file_assistant_test.cc
index ed47ca3a6b..e8a7381296 100644
--- a/runtime/oat_file_assistant_test.cc
+++ b/runtime/oat_file_assistant_test.cc
@@ -1437,6 +1437,7 @@ TEST_F(OatFileAssistantTest, GetDexOptNeededWithOutOfDateContext) {
TEST_F(OatFileAssistantTest, GetDexLocation) {
std::string dex_location = GetScratchDir() + "/TestDex.jar";
std::string oat_location = GetOdexDir() + "/TestDex.odex";
+ std::string art_location = GetOdexDir() + "/TestDex.art";
// Start the runtime to initialize the system's class loader.
Thread::Current()->TransitionFromSuspendedToRunnable();
@@ -1463,6 +1464,7 @@ TEST_F(OatFileAssistantTest, GetDexLocation) {
args.push_back("--dex-file=" + dex_location);
args.push_back("--dex-location=TestDex.jar");
args.push_back("--oat-file=" + oat_location);
+ args.push_back("--app-image-file=" + art_location);
std::string error_msg;
ASSERT_TRUE(DexoptTest::Dex2Oat(args, &error_msg)) << error_msg;
}
@@ -1490,6 +1492,7 @@ TEST_F(OatFileAssistantTest, SystemFrameworkDir) {
odex_dir = odex_dir + std::string(GetInstructionSetString(kRuntimeISA));
mkdir(odex_dir.c_str(), 0700);
std::string oat_location = odex_dir + "/" + filebase + ".odex";
+ std::string art_location = odex_dir + "/" + filebase + ".art";
// Clean up in case previous run crashed.
remove(oat_location.c_str());
@@ -1527,6 +1530,7 @@ TEST_F(OatFileAssistantTest, SystemFrameworkDir) {
args.push_back("--dex-file=" + dex_location);
args.push_back("--dex-location=" + filebase + ".jar");
args.push_back("--oat-file=" + oat_location);
+ args.push_back("--app-image-file=" + art_location);
std::string error_msg;
ASSERT_TRUE(DexoptTest::Dex2Oat(args, &error_msg)) << error_msg;
}
diff --git a/runtime/oat_file_manager.cc b/runtime/oat_file_manager.cc
index ff743d5158..7101a23d43 100644
--- a/runtime/oat_file_manager.cc
+++ b/runtime/oat_file_manager.cc
@@ -492,13 +492,14 @@ std::vector<std::unique_ptr<const DexFile>> OatFileManager::OpenDexFilesFromOat(
const OatFile* source_oat_file = nullptr;
CheckCollisionResult check_collision_result = CheckCollisionResult::kPerformedHasCollisions;
std::string error_msg;
+ bool accept_oat_file = false;
if ((class_loader != nullptr || dex_elements != nullptr) && oat_file != nullptr) {
// Prevent oat files from being loaded if no class_loader or dex_elements are provided.
// This can happen when the deprecated DexFile.<init>(String) is called directly, and it
// could load oat files without checking the classpath, which would be incorrect.
// Take the file only if it has no collisions, or we must take it because of preopting.
check_collision_result = CheckCollision(oat_file.get(), context.get(), /*out*/ &error_msg);
- bool accept_oat_file = AcceptOatFile(check_collision_result);
+ accept_oat_file = AcceptOatFile(check_collision_result);
if (!accept_oat_file) {
// Failed the collision check. Print warning.
if (runtime->IsDexFileFallbackEnabled()) {
@@ -531,30 +532,24 @@ std::vector<std::unique_ptr<const DexFile>> OatFileManager::OpenDexFilesFromOat(
LOG(WARNING) << error_msg;
}
-
- if (accept_oat_file) {
- VLOG(class_linker) << "Registering " << oat_file->GetLocation();
- source_oat_file = RegisterOatFile(std::move(oat_file));
- *out_oat_file = source_oat_file;
- }
}
std::vector<std::unique_ptr<const DexFile>> dex_files;
// Load the dex files from the oat file.
- if (source_oat_file != nullptr) {
- bool added_image_space = false;
- if (source_oat_file->IsExecutable()) {
+ bool added_image_space = false;
+ if (accept_oat_file) {
+ if (oat_file->IsExecutable()) {
ScopedTrace app_image_timing("AppImage:Loading");
// We need to throw away the image space if we are debuggable but the oat-file source of the
// image is not otherwise we might get classes with inlined methods or other such things.
std::unique_ptr<gc::space::ImageSpace> image_space;
if (ShouldLoadAppImage(check_collision_result,
- source_oat_file,
+ oat_file.get(),
context.get(),
&error_msg)) {
- image_space = oat_file_assistant.OpenImageSpace(source_oat_file);
+ image_space = oat_file_assistant.OpenImageSpace(oat_file.get());
}
if (image_space != nullptr) {
ScopedObjectAccess soa(self);
@@ -606,9 +601,9 @@ std::vector<std::unique_ptr<const DexFile>> OatFileManager::OpenDexFilesFromOat(
}
}
}
- if (!added_image_space) {
+ if (!added_image_space && !oat_file->RequiresImage()) {
DCHECK(dex_files.empty());
- dex_files = oat_file_assistant.LoadDexFiles(*source_oat_file, dex_location);
+ dex_files = oat_file_assistant.LoadDexFiles(*oat_file.get(), dex_location);
// Register for tracking.
for (const auto& dex_file : dex_files) {
@@ -616,7 +611,7 @@ std::vector<std::unique_ptr<const DexFile>> OatFileManager::OpenDexFilesFromOat(
}
}
if (dex_files.empty()) {
- error_msgs->push_back("Failed to open dex files from " + source_oat_file->GetLocation());
+ error_msgs->push_back("Failed to open dex files from " + oat_file->GetLocation());
} else {
// Opened dex files from an oat file, madvise them to their loaded state.
for (const std::unique_ptr<const DexFile>& dex_file : dex_files) {
@@ -625,6 +620,12 @@ std::vector<std::unique_ptr<const DexFile>> OatFileManager::OpenDexFilesFromOat(
}
}
+ if (accept_oat_file && (added_image_space || !oat_file->RequiresImage())) {
+ VLOG(class_linker) << "Registering " << oat_file->GetLocation();
+ source_oat_file = RegisterOatFile(std::move(oat_file));
+ *out_oat_file = source_oat_file;
+ }
+
// Fall back to running out of the original dex file if we couldn't load any
// dex_files from the oat file.
if (dex_files.empty()) {
diff --git a/test/2231-oat-require-app-image/expected.txt b/test/2231-oat-require-app-image/expected.txt
new file mode 100644
index 0000000000..95d58e9d79
--- /dev/null
+++ b/test/2231-oat-require-app-image/expected.txt
@@ -0,0 +1,2 @@
+JNI_OnLoad called
+Test passed.
diff --git a/test/2231-oat-require-app-image/info.txt b/test/2231-oat-require-app-image/info.txt
new file mode 100644
index 0000000000..8e0b0693de
--- /dev/null
+++ b/test/2231-oat-require-app-image/info.txt
@@ -0,0 +1 @@
+Make sure speed-profile OAT files do not load without an AppImage \ No newline at end of file
diff --git a/test/2231-oat-require-app-image/profile b/test/2231-oat-require-app-image/profile
new file mode 100644
index 0000000000..36fb1bae49
--- /dev/null
+++ b/test/2231-oat-require-app-image/profile
@@ -0,0 +1 @@
+LMain; \ No newline at end of file
diff --git a/test/2231-oat-require-app-image/run b/test/2231-oat-require-app-image/run
new file mode 100644
index 0000000000..c258a0ef45
--- /dev/null
+++ b/test/2231-oat-require-app-image/run
@@ -0,0 +1,18 @@
+#!/bin/bash
+#
+# Copyright (C) 2020 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.
+
+# We need a profile to tell dex2oat to include classes in the final app image
+exec ${RUN} --no-app-image --profile $@
diff --git a/test/2231-oat-require-app-image/src/Main.java b/test/2231-oat-require-app-image/src/Main.java
new file mode 100644
index 0000000000..1bac2cba7e
--- /dev/null
+++ b/test/2231-oat-require-app-image/src/Main.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+public class Main {
+ public static void main(String[] args) {
+ System.loadLibrary(args[0]);
+
+ if ("speed-profile".equals(getCompilerFilter(Main.class)) && !hasAppImage() && hasOatFile()) {
+ System.out.println("Error: Loaded OAT file with no app image in speed-profile mode");
+ }
+
+ System.out.println("Test passed.");
+ }
+
+ private native static boolean hasAppImage();
+ private native static boolean hasOatFile();
+ private native static Object getCompilerFilter(Class c);
+}
diff --git a/test/common/runtime_state.cc b/test/common/runtime_state.cc
index 6c76288663..48158e28ba 100644
--- a/test/common/runtime_state.cc
+++ b/test/common/runtime_state.cc
@@ -102,6 +102,14 @@ extern "C" JNIEXPORT jboolean JNICALL Java_Main_hasImage(JNIEnv* env ATTRIBUTE_U
return Runtime::Current()->GetHeap()->HasBootImageSpace();
}
+// public static native boolean hasAppImage();
+
+extern "C" JNIEXPORT jboolean JNICALL Java_Main_hasAppImage(JNIEnv* env,
+ jclass cls ATTRIBUTE_UNUSED) {
+ ScopedObjectAccess soa(env);
+ return Runtime::Current()->GetHeap()->HasAppImageSpace();
+}
+
// public static native boolean isImageDex2OatEnabled();
extern "C" JNIEXPORT jboolean JNICALL Java_Main_isImageDex2OatEnabled(JNIEnv* env ATTRIBUTE_UNUSED,