summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--compiler/driver/compiler_driver.cc15
-rw-r--r--runtime/class_linker.cc11
-rw-r--r--runtime/class_linker.h6
-rw-r--r--runtime/generated/asm_support_gen.h2
-rw-r--r--runtime/mirror/class.h7
-rw-r--r--runtime/oat.h4
-rw-r--r--runtime/oat_file_assistant_test.cc7
-rw-r--r--runtime/oat_file_manager.cc5
-rw-r--r--test/138-duplicate-classes-check2/src/FancyLoader.java228
-rw-r--r--test/138-duplicate-classes-check2/src/Main.java37
10 files changed, 70 insertions, 252 deletions
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index c04e45d334..ff92ac43b8 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -2246,7 +2246,7 @@ class InitializeClassVisitor : public CompilationVisitor {
const bool is_boot_image = manager_->GetCompiler()->GetCompilerOptions().IsBootImage();
const bool is_app_image = manager_->GetCompiler()->GetCompilerOptions().IsAppImage();
- mirror::Class::Status old_status = klass->GetStatus();;
+ mirror::Class::Status old_status = klass->GetStatus();
// Only try to initialize classes that were successfully verified.
if (klass->IsVerified()) {
// Don't initialize classes in boot space when compiling app image
@@ -2364,6 +2364,14 @@ class InitializeClassVisitor : public CompilationVisitor {
}
}
}
+ // If the class still isn't initialized, at least try some checks that initialization
+ // would do so they can be skipped at runtime.
+ if (!klass->IsInitialized() &&
+ manager_->GetClassLinker()->ValidateSuperClassDescriptors(klass)) {
+ old_status = mirror::Class::kStatusSuperclassValidated;
+ } else {
+ soa.Self()->ClearException();
+ }
soa.Self()->AssertNoPendingException();
}
}
@@ -2861,13 +2869,14 @@ bool CompilerDriver::GetCompiledClass(ClassReference ref, mirror::Class::Status*
void CompilerDriver::RecordClassStatus(ClassReference ref, mirror::Class::Status status) {
switch (status) {
- case mirror::Class::kStatusNotReady:
case mirror::Class::kStatusErrorResolved:
case mirror::Class::kStatusErrorUnresolved:
+ case mirror::Class::kStatusNotReady:
+ case mirror::Class::kStatusResolved:
case mirror::Class::kStatusRetryVerificationAtRuntime:
case mirror::Class::kStatusVerified:
+ case mirror::Class::kStatusSuperclassValidated:
case mirror::Class::kStatusInitialized:
- case mirror::Class::kStatusResolved:
break; // Expected states.
default:
LOG(FATAL) << "Unexpected class status for class "
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index a5d4540f88..1c3375c93a 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -4405,8 +4405,7 @@ bool ClassLinker::VerifyClassUsingOatFile(const DexFile& dex_file,
uint16_t class_def_index = klass->GetDexClassDefIndex();
oat_file_class_status = oat_dex_file->GetOatClass(class_def_index).GetStatus();
- if (oat_file_class_status == mirror::Class::kStatusVerified ||
- oat_file_class_status == mirror::Class::kStatusInitialized) {
+ if (oat_file_class_status >= mirror::Class::kStatusVerified) {
return true;
}
// If we only verified a subset of the classes at compile time, we can end up with classes that
@@ -4885,7 +4884,13 @@ bool ClassLinker::InitializeClass(Thread* self, Handle<mirror::Class> klass,
return WaitForInitializeClass(klass, self, lock);
}
- if (!ValidateSuperClassDescriptors(klass)) {
+ bool has_oat_class = false;
+ const OatFile::OatClass oat_class =
+ (Runtime::Current()->IsStarted() && !Runtime::Current()->IsAotCompiler())
+ ? OatFile::FindOatClass(klass->GetDexFile(), klass->GetDexClassDefIndex(), &has_oat_class)
+ : OatFile::OatClass::Invalid();
+ if (oat_class.GetStatus() < mirror::Class::kStatusSuperclassValidated &&
+ !ValidateSuperClassDescriptors(klass)) {
mirror::Class::SetStatus(klass, mirror::Class::kStatusErrorResolved, self);
return false;
}
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index 8b8a6fd420..864d37fa89 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -675,6 +675,10 @@ class ClassLinker {
void VisitClassLoaders(ClassLoaderVisitor* visitor) const
REQUIRES_SHARED(Locks::classlinker_classes_lock_, Locks::mutator_lock_);
+ // Checks that a class and its superclass from another class loader have the same virtual methods.
+ bool ValidateSuperClassDescriptors(Handle<mirror::Class> klass)
+ REQUIRES_SHARED(Locks::mutator_lock_);
+
struct DexCacheData {
// Construct an invalid data object.
DexCacheData()
@@ -907,8 +911,6 @@ class ClassLinker {
bool WaitForInitializeClass(Handle<mirror::Class> klass,
Thread* self,
ObjectLock<mirror::Class>& lock);
- bool ValidateSuperClassDescriptors(Handle<mirror::Class> klass)
- REQUIRES_SHARED(Locks::mutator_lock_);
bool IsSameDescriptorInDifferentClassContexts(Thread* self,
const char* descriptor,
diff --git a/runtime/generated/asm_support_gen.h b/runtime/generated/asm_support_gen.h
index 3a7f21de67..06e4704c1c 100644
--- a/runtime/generated/asm_support_gen.h
+++ b/runtime/generated/asm_support_gen.h
@@ -48,7 +48,7 @@ DEFINE_CHECK_EQ(static_cast<int32_t>(CODEITEM_INSNS_OFFSET), (static_cast<int32_
DEFINE_CHECK_EQ(static_cast<int32_t>(MIRROR_OBJECT_CLASS_OFFSET), (static_cast<int32_t>(art::mirror::Object:: ClassOffset().Int32Value())))
#define MIRROR_OBJECT_LOCK_WORD_OFFSET 4
DEFINE_CHECK_EQ(static_cast<int32_t>(MIRROR_OBJECT_LOCK_WORD_OFFSET), (static_cast<int32_t>(art::mirror::Object:: MonitorOffset().Int32Value())))
-#define MIRROR_CLASS_STATUS_INITIALIZED 0xa
+#define MIRROR_CLASS_STATUS_INITIALIZED 0xb
DEFINE_CHECK_EQ(static_cast<uint32_t>(MIRROR_CLASS_STATUS_INITIALIZED), (static_cast<uint32_t>((art::mirror::Class::kStatusInitialized))))
#define ACCESS_FLAGS_CLASS_IS_FINALIZABLE 0x80000000
DEFINE_CHECK_EQ(static_cast<uint32_t>(ACCESS_FLAGS_CLASS_IS_FINALIZABLE), (static_cast<uint32_t>((art::kAccClassIsFinalizable))))
diff --git a/runtime/mirror/class.h b/runtime/mirror/class.h
index b60ddcf60c..e516a0636b 100644
--- a/runtime/mirror/class.h
+++ b/runtime/mirror/class.h
@@ -138,9 +138,10 @@ class MANAGED Class FINAL : public Object {
kStatusRetryVerificationAtRuntime = 6, // Compile time verification failed, retry at runtime.
kStatusVerifyingAtRuntime = 7, // Retrying verification at runtime.
kStatusVerified = 8, // Logically part of linking; done pre-init.
- kStatusInitializing = 9, // Class init in progress.
- kStatusInitialized = 10, // Ready to go.
- kStatusMax = 11,
+ kStatusSuperclassValidated = 9, // Superclass validation part of init done.
+ kStatusInitializing = 10, // Class init in progress.
+ kStatusInitialized = 11, // Ready to go.
+ kStatusMax = 12,
};
template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
diff --git a/runtime/oat.h b/runtime/oat.h
index 5e61907d82..f4edb16bce 100644
--- a/runtime/oat.h
+++ b/runtime/oat.h
@@ -32,8 +32,8 @@ class InstructionSetFeatures;
class PACKED(4) OatHeader {
public:
static constexpr uint8_t kOatMagic[] = { 'o', 'a', 't', '\n' };
- // Last oat version changed reason: update classpath key format.
- static constexpr uint8_t kOatVersion[] = { '1', '2', '8', '\0' };
+ // Last oat version changed reason: add new class status to skip superclass validation.
+ static constexpr uint8_t kOatVersion[] = { '1', '2', '9', '\0' };
static constexpr const char* kImageLocationKey = "image-location";
static constexpr const char* kDex2OatCmdLineKey = "dex2oat-cmdline";
diff --git a/runtime/oat_file_assistant_test.cc b/runtime/oat_file_assistant_test.cc
index 3619129718..1ecdd0d77e 100644
--- a/runtime/oat_file_assistant_test.cc
+++ b/runtime/oat_file_assistant_test.cc
@@ -23,6 +23,7 @@
#include "art_field-inl.h"
#include "class_linker-inl.h"
+#include "common_runtime_test.h"
#include "dexopt_test.h"
#include "oat_file_assistant.h"
#include "oat_file_manager.h"
@@ -1059,7 +1060,7 @@ class RaceGenerateTask : public Task {
const OatFile* oat_file = nullptr;
dex_files = Runtime::Current()->GetOatFileManager().OpenDexFilesFromOat(
dex_location_.c_str(),
- /*class_loader*/nullptr,
+ Runtime::Current()->GetSystemClassLoader(),
/*dex_elements*/nullptr,
&oat_file,
&error_msgs);
@@ -1089,6 +1090,10 @@ TEST_F(OatFileAssistantTest, RaceToGenerate) {
std::string dex_location = GetScratchDir() + "/RaceToGenerate.jar";
std::string oat_location = GetOdexDir() + "/RaceToGenerate.oat";
+ // Start the runtime to initialize the system's class loader.
+ Thread::Current()->TransitionFromSuspendedToRunnable();
+ runtime_->Start();
+
// We use the lib core dex file, because it's large, and hopefully should
// take a while to generate.
Copy(GetLibCoreDexFileNames()[0], dex_location);
diff --git a/runtime/oat_file_manager.cc b/runtime/oat_file_manager.cc
index b166961795..dc542d46d9 100644
--- a/runtime/oat_file_manager.cc
+++ b/runtime/oat_file_manager.cc
@@ -665,7 +665,10 @@ std::vector<std::unique_ptr<const DexFile>> OatFileManager::OpenDexFilesFromOat(
// Get the oat file on disk.
std::unique_ptr<const OatFile> oat_file(oat_file_assistant.GetBestOatFile().release());
- if (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.
+ if ((class_loader != nullptr || dex_elements != nullptr) && oat_file != nullptr) {
// Take the file only if it has no collisions, or we must take it because of preopting.
bool accept_oat_file =
!HasCollisions(oat_file.get(), class_loader, dex_elements, /*out*/ &error_msg);
diff --git a/test/138-duplicate-classes-check2/src/FancyLoader.java b/test/138-duplicate-classes-check2/src/FancyLoader.java
deleted file mode 100644
index 58b7ec49d3..0000000000
--- a/test/138-duplicate-classes-check2/src/FancyLoader.java
+++ /dev/null
@@ -1,228 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.RandomAccessFile;
-import java.lang.reflect.Constructor;
-import java.lang.reflect.Method;
-import java.lang.reflect.InvocationTargetException;
-
-/**
- * A class loader with atypical behavior: we try to load a private
- * class implementation before asking the system or boot loader. This
- * is used to create multiple classes with identical names in a single VM.
- *
- * If DexFile is available, we use that; if not, we assume we're not in
- * Dalvik and instantiate the class with defineClass().
- *
- * The location of the DEX files and class data is dependent upon the
- * test framework.
- */
-public class FancyLoader extends ClassLoader {
- /* this is where the "alternate" .class files live */
- static final String CLASS_PATH = "classes-ex/";
-
- /* this is the "alternate" DEX/Jar file */
- static final String DEX_FILE = System.getenv("DEX_LOCATION") +
- "/138-duplicate-classes-check2-ex.jar";
-
- /* on Dalvik, this is a DexFile; otherwise, it's null */
- private Class<?> mDexClass;
-
- private Object mDexFile;
-
- /**
- * Construct FancyLoader, grabbing a reference to the DexFile class
- * if we're running under Dalvik.
- */
- public FancyLoader(ClassLoader parent) {
- super(parent);
-
- try {
- mDexClass = parent.loadClass("dalvik.system.DexFile");
- } catch (ClassNotFoundException cnfe) {
- // ignore -- not running Dalvik
- }
- }
-
- /**
- * Finds the class with the specified binary name.
- *
- * We search for a file in CLASS_PATH or pull an entry from DEX_FILE.
- * If we don't find a match, we throw an exception.
- */
- protected Class<?> findClass(String name) throws ClassNotFoundException
- {
- if (mDexClass != null) {
- return findClassDalvik(name);
- } else {
- return findClassNonDalvik(name);
- }
- }
-
- /**
- * Finds the class with the specified binary name, from a DEX file.
- */
- private Class<?> findClassDalvik(String name)
- throws ClassNotFoundException {
-
- if (mDexFile == null) {
- synchronized (FancyLoader.class) {
- Constructor<?> ctor;
- /*
- * Construct a DexFile object through reflection.
- */
- try {
- ctor = mDexClass.getConstructor(String.class);
- } catch (NoSuchMethodException nsme) {
- throw new ClassNotFoundException("getConstructor failed",
- nsme);
- }
-
- try {
- mDexFile = ctor.newInstance(DEX_FILE);
- } catch (InstantiationException ie) {
- throw new ClassNotFoundException("newInstance failed", ie);
- } catch (IllegalAccessException iae) {
- throw new ClassNotFoundException("newInstance failed", iae);
- } catch (InvocationTargetException ite) {
- throw new ClassNotFoundException("newInstance failed", ite);
- }
- }
- }
-
- /*
- * Call DexFile.loadClass(String, ClassLoader).
- */
- Method meth;
-
- try {
- meth = mDexClass.getMethod("loadClass", String.class, ClassLoader.class);
- } catch (NoSuchMethodException nsme) {
- throw new ClassNotFoundException("getMethod failed", nsme);
- }
-
- try {
- meth.invoke(mDexFile, name, this);
- } catch (IllegalAccessException iae) {
- throw new ClassNotFoundException("loadClass failed", iae);
- } catch (InvocationTargetException ite) {
- throw new ClassNotFoundException("loadClass failed",
- ite.getCause());
- }
-
- return null;
- }
-
- /**
- * Finds the class with the specified binary name, from .class files.
- */
- private Class<?> findClassNonDalvik(String name)
- throws ClassNotFoundException {
-
- String pathName = CLASS_PATH + name + ".class";
- //System.out.println("--- Fancy: looking for " + pathName);
-
- File path = new File(pathName);
- RandomAccessFile raf;
-
- try {
- raf = new RandomAccessFile(path, "r");
- } catch (FileNotFoundException fnfe) {
- throw new ClassNotFoundException("Not found: " + pathName);
- }
-
- /* read the entire file in */
- byte[] fileData;
- try {
- fileData = new byte[(int) raf.length()];
- raf.readFully(fileData);
- } catch (IOException ioe) {
- throw new ClassNotFoundException("Read error: " + pathName);
- } finally {
- try {
- raf.close();
- } catch (IOException ioe) {
- // drop
- }
- }
-
- /* create the class */
- //System.out.println("--- Fancy: defining " + name);
- try {
- return defineClass(name, fileData, 0, fileData.length);
- } catch (Throwable th) {
- throw new ClassNotFoundException("defineClass failed", th);
- }
- }
-
- /**
- * Load a class.
- *
- * Normally a class loader wouldn't override this, but we want our
- * version of the class to take precedence over an already-loaded
- * version.
- *
- * We still want the system classes (e.g. java.lang.Object) from the
- * bootstrap class loader.
- */
- protected Class<?> loadClass(String name, boolean resolve)
- throws ClassNotFoundException
- {
- Class<?> res;
-
- /*
- * 1. Invoke findLoadedClass(String) to check if the class has
- * already been loaded.
- *
- * This doesn't change.
- */
- res = findLoadedClass(name);
- if (res != null) {
- System.out.println("FancyLoader.loadClass: "
- + name + " already loaded");
- if (resolve)
- resolveClass(res);
- return res;
- }
-
- /*
- * 3. Invoke the findClass(String) method to find the class.
- */
- try {
- res = findClass(name);
- if (resolve)
- resolveClass(res);
- }
- catch (ClassNotFoundException e) {
- // we couldn't find it, so eat the exception and keep going
- }
-
- /*
- * 2. Invoke the loadClass method on the parent class loader. If
- * the parent loader is null the class loader built-in to the
- * virtual machine is used, instead.
- *
- * (Since we're not in java.lang, we can't actually invoke the
- * parent's loadClass() method, but we passed our parent to the
- * super-class which can take care of it for us.)
- */
- res = super.loadClass(name, resolve); // returns class or throws
- return res;
- }
-}
diff --git a/test/138-duplicate-classes-check2/src/Main.java b/test/138-duplicate-classes-check2/src/Main.java
index faf8b5d337..588e5eb4f5 100644
--- a/test/138-duplicate-classes-check2/src/Main.java
+++ b/test/138-duplicate-classes-check2/src/Main.java
@@ -15,12 +15,30 @@
*/
import java.io.File;
+import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
/**
* Structural hazard test.
*/
public class Main {
+ public static String TEST_NAME = "138-duplicate-classes-check2";
+
+ public static ClassLoader getClassLoaderFor(String location) throws Exception {
+ try {
+ Class<?> class_loader_class = Class.forName("dalvik.system.PathClassLoader");
+ Constructor<?> ctor =
+ class_loader_class.getConstructor(String.class, ClassLoader.class);
+ /* on Dalvik, this is a DexFile; otherwise, it's null */
+ return (ClassLoader) ctor.newInstance(location + "/" + TEST_NAME + "-ex.jar",
+ Main.class.getClassLoader());
+ } catch (ClassNotFoundException e) {
+ // Running on RI. Use URLClassLoader.
+ return new java.net.URLClassLoader(
+ new java.net.URL[] { new java.net.URL("file://" + location + "/classes-ex/") });
+ }
+ }
+
public static void main(String[] args) {
new Main().run();
}
@@ -29,15 +47,18 @@ public class Main {
System.out.println(new A().i);
// Now run the class from the -ex file.
-
- FancyLoader loader = new FancyLoader(getClass().getClassLoader());
-
try {
- Class<?> testEx = loader.loadClass("TestEx");
- Method test = testEx.getDeclaredMethod("test");
- test.invoke(null);
- } catch (Exception exc) {
- exc.printStackTrace(System.out);
+ /* this is the "alternate" DEX/Jar file */
+ ClassLoader new_loader = getClassLoaderFor(System.getenv("DEX_LOCATION"));
+ Class<?> klass = (Class<?>) new_loader.loadClass("TestEx");
+ if (klass == null) {
+ throw new AssertionError("loadClass failed");
+ }
+ Method run_test = klass.getMethod("test");
+ run_test.invoke(null);
+ } catch (Exception e) {
+ System.out.println(e.toString());
+ e.printStackTrace(System.out);
}
}
}