Merge "ART: X86: Improve multiply in div/rem by literal"
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index ad436d0..1e64c00 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -785,7 +785,19 @@
return NULL;
}
-static bool LoadMultiDexFilesFromOatFile(const OatFile* oat_file, const char* dex_location,
+
+// Loads all multi dex files from the given oat file returning true on success.
+//
+// Parameters:
+// oat_file - the oat file to load from
+// dex_location - the dex location used to generate the oat file
+// dex_location_checksum - the checksum of the dex_location (may be null for pre-opted files)
+// generated - whether or not the oat_file existed before or was just (re)generated
+// error_msgs - any error messages will be appended here
+// dex_files - the loaded dex_files will be appended here (only if the loading succeeds)
+static bool LoadMultiDexFilesFromOatFile(const OatFile* oat_file,
+ const char* dex_location,
+ const uint32_t* dex_location_checksum,
bool generated,
std::vector<std::string>* error_msgs,
std::vector<const DexFile*>* dex_files) {
@@ -800,12 +812,20 @@
std::string next_name_str = DexFile::GetMultiDexClassesDexName(i, dex_location);
const char* next_name = next_name_str.c_str();
- uint32_t dex_location_checksum;
- uint32_t* dex_location_checksum_pointer = &dex_location_checksum;
+ uint32_t next_location_checksum;
+ uint32_t* next_location_checksum_pointer = &next_location_checksum;
std::string error_msg;
- if (!DexFile::GetChecksum(next_name, dex_location_checksum_pointer, &error_msg)) {
+ if ((i == 0) && (strcmp(next_name, dex_location) == 0)) {
+ // When i=0 the multidex name should be the same as the location name. We already have the
+ // checksum it so we don't need to recompute it.
+ if (dex_location_checksum == nullptr) {
+ next_location_checksum_pointer = nullptr;
+ } else {
+ next_location_checksum = *dex_location_checksum;
+ }
+ } else if (!DexFile::GetChecksum(next_name, next_location_checksum_pointer, &error_msg)) {
DCHECK_EQ(false, i == 0 && generated);
- dex_location_checksum_pointer = nullptr;
+ next_location_checksum_pointer = nullptr;
}
const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(next_name, nullptr, false);
@@ -814,7 +834,7 @@
if (i == 0 && generated) {
std::string error_msg;
error_msg = StringPrintf("\nFailed to find dex file '%s' (checksum 0x%x) in generated out "
- " file'%s'", dex_location, dex_location_checksum,
+ " file'%s'", dex_location, next_location_checksum,
oat_file->GetLocation().c_str());
error_msgs->push_back(error_msg);
}
@@ -823,8 +843,8 @@
// Checksum test. Test must succeed when generated.
success = !generated;
- if (dex_location_checksum_pointer != nullptr) {
- success = dex_location_checksum == oat_dex_file->GetDexFileLocationChecksum();
+ if (next_location_checksum_pointer != nullptr) {
+ success = next_location_checksum == oat_dex_file->GetDexFileLocationChecksum();
}
if (success) {
@@ -840,7 +860,7 @@
// When we generated the file, we expect success, or something is terribly wrong.
CHECK_EQ(false, generated && !success)
<< "dex_location=" << next_name << " oat_location=" << oat_file->GetLocation().c_str()
- << std::hex << " dex_location_checksum=" << dex_location_checksum
+ << std::hex << " dex_location_checksum=" << next_location_checksum
<< " OatDexFile::GetLocationChecksum()=" << oat_dex_file->GetDexFileLocationChecksum();
}
@@ -877,6 +897,7 @@
bool have_checksum = true;
std::string checksum_error_msg;
if (!DexFile::GetChecksum(dex_location, dex_location_checksum_pointer, &checksum_error_msg)) {
+ // This happens for pre-opted files since the corresponding dex files are no longer on disk.
dex_location_checksum_pointer = nullptr;
have_checksum = false;
}
@@ -942,8 +963,9 @@
// 3) If we have an oat file, check all contained multidex files for our dex_location.
// Note: LoadMultiDexFilesFromOatFile will check for nullptr in the first argument.
- bool success = LoadMultiDexFilesFromOatFile(open_oat_file.get(), dex_location, false, error_msgs,
- dex_files);
+ bool success = LoadMultiDexFilesFromOatFile(open_oat_file.get(), dex_location,
+ dex_location_checksum_pointer,
+ false, error_msgs, dex_files);
if (success) {
const OatFile* oat_file = open_oat_file.release(); // Avoid deleting it.
if (needs_registering) {
@@ -1004,8 +1026,8 @@
}
// Try to load again, but stronger checks.
- success = LoadMultiDexFilesFromOatFile(open_oat_file.get(), dex_location, true, error_msgs,
- dex_files);
+ success = LoadMultiDexFilesFromOatFile(open_oat_file.get(), dex_location, dex_location_checksum_pointer,
+ true, error_msgs, dex_files);
if (success) {
RegisterOatFile(open_oat_file.release());
return true;
@@ -1189,24 +1211,18 @@
return false;
}
- if (dex_location_checksum != oat_dex_file->GetDexFileLocationChecksum()) {
- *error_msg = StringPrintf("oat file '%s' mismatch (0x%x) with '%s' (0x%x)",
- oat_file->GetLocation().c_str(),
- oat_dex_file->GetDexFileLocationChecksum(),
- dex_location, dex_location_checksum);
- return false;
- }
+ DCHECK_EQ(dex_location_checksum, oat_dex_file->GetDexFileLocationChecksum());
return true;
}
bool ClassLinker::VerifyOatWithDexFile(const OatFile* oat_file,
const char* dex_location,
+ const uint32_t* dex_location_checksum,
std::string* error_msg) {
CHECK(oat_file != nullptr);
CHECK(dex_location != nullptr);
std::unique_ptr<const DexFile> dex_file;
- uint32_t dex_location_checksum;
- if (!DexFile::GetChecksum(dex_location, &dex_location_checksum, error_msg)) {
+ if (dex_location_checksum == nullptr) {
// If no classes.dex found in dex_location, it has been stripped or is corrupt, assume oat is
// up-to-date. This is the common case in user builds for jar's and apk's in the /system
// directory.
@@ -1219,13 +1235,13 @@
}
dex_file.reset(oat_dex_file->OpenDexFile(error_msg));
} else {
- bool verified = VerifyOatAndDexFileChecksums(oat_file, dex_location, dex_location_checksum,
+ bool verified = VerifyOatAndDexFileChecksums(oat_file, dex_location, *dex_location_checksum,
kRuntimeISA, error_msg);
if (!verified) {
return false;
}
dex_file.reset(oat_file->GetOatDexFile(dex_location,
- &dex_location_checksum)->OpenDexFile(error_msg));
+ dex_location_checksum)->OpenDexFile(error_msg));
}
return dex_file.get() != nullptr;
}
@@ -1249,7 +1265,8 @@
dex_location));
return nullptr;
} else if (oat_file->IsExecutable() &&
- !VerifyOatWithDexFile(oat_file.get(), dex_location, &error_msg)) {
+ !VerifyOatWithDexFile(oat_file.get(), dex_location,
+ dex_location_checksum, &error_msg)) {
error_msgs->push_back(StringPrintf("Failed to verify oat file '%s' found for dex location "
"'%s': %s", oat_file->GetLocation().c_str(), dex_location,
error_msg.c_str()));
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index 7750c8e..d1f5aa0 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -613,9 +613,18 @@
bool* obsolete_file_cleanup_failed)
LOCKS_EXCLUDED(dex_lock_, Locks::mutator_lock_);
- // verify an oat file with the given dex file. Will return false when the dex file could not be
- // verified. Will return true otherwise.
+ // Verifies:
+ // - that the oat file contains the dex file (with a matching checksum, which may be null if the
+ // file was pre-opted)
+ // - the checksums of the oat file (against the image space)
+ // - the checksum of the dex file against dex_location_checksum
+ // - that the dex file can be opened
+ // Returns true iff all verification succeed.
+ //
+ // The dex_location is the dex location as stored in the oat file header.
+ // (see DexFile::GetDexCanonicalLocation for a description of location conventions)
bool VerifyOatWithDexFile(const OatFile* oat_file, const char* dex_location,
+ const uint32_t* dex_location_checksum,
std::string* error_msg);
mirror::ArtMethod* CreateProxyConstructor(Thread* self, ConstHandle<mirror::Class> klass,
diff --git a/runtime/fault_handler.cc b/runtime/fault_handler.cc
index cc1038c..47696f9 100644
--- a/runtime/fault_handler.cc
+++ b/runtime/fault_handler.cc
@@ -186,8 +186,6 @@
action.sa_restorer = nullptr;
#endif
- bool signal_handled = false;
-
// Catch SIGSEGV and SIGABRT to invoke our nested handler
int e1 = sigaction(SIGSEGV, &action, &oldsegvaction);
int e2 = sigaction(SIGABRT, &action, &oldabortaction);
@@ -200,8 +198,12 @@
if (setjmp(*self->GetNestedSignalState()) == 0) {
for (const auto& handler : other_handlers_) {
if (handler->Action(sig, info, context)) {
- signal_handled = true;
- break;
+ // Restore the signal handlers, reinit the fault manager and return. Signal was
+ // handled.
+ sigaction(SIGSEGV, &oldsegvaction, nullptr);
+ sigaction(SIGABRT, &oldabortaction, nullptr);
+ fault_manager.Init();
+ return;
}
}
} else {
@@ -216,13 +218,11 @@
// Now put the fault manager back in place.
fault_manager.Init();
- if (!signal_handled) {
- // Set a breakpoint in this function to catch unhandled signals.
- art_sigsegv_fault();
+ // Set a breakpoint in this function to catch unhandled signals.
+ art_sigsegv_fault();
- // Pass this on to the next handler in the chain, or the default if none.
- InvokeUserSignalHandler(sig, info, context);
- }
+ // Pass this on to the next handler in the chain, or the default if none.
+ InvokeUserSignalHandler(sig, info, context);
}
void FaultManager::AddHandler(FaultHandler* handler, bool generated_code) {
diff --git a/runtime/native/dalvik_system_ZygoteHooks.cc b/runtime/native/dalvik_system_ZygoteHooks.cc
index df6055d..c3c8c25 100644
--- a/runtime/native/dalvik_system_ZygoteHooks.cc
+++ b/runtime/native/dalvik_system_ZygoteHooks.cc
@@ -17,9 +17,11 @@
#include <stdlib.h>
#include "debugger.h"
+#include "instruction_set.h"
#include "java_vm_ext.h"
#include "jni_internal.h"
#include "JNIHelp.h"
+#include "ScopedUtfChars.h"
#include "thread-inl.h"
#if defined(HAVE_PRCTL)
@@ -102,17 +104,27 @@
return reinterpret_cast<jlong>(self);
}
-static void ZygoteHooks_nativePostForkChild(JNIEnv* env, jclass, jlong token, jint debug_flags) {
+static void ZygoteHooks_nativePostForkChild(JNIEnv* env, jclass, jlong token, jint debug_flags,
+ jstring instruction_set) {
Thread* thread = reinterpret_cast<Thread*>(token);
// Our system thread ID, etc, has changed so reset Thread state.
thread->InitAfterFork();
EnableDebugFeatures(debug_flags);
- Runtime::Current()->DidForkFromZygote();
+
+ Runtime::NativeBridgeAction action = Runtime::NativeBridgeAction::kUnload;
+ if (instruction_set != nullptr) {
+ ScopedUtfChars isa_string(env, instruction_set);
+ InstructionSet isa = GetInstructionSetFromString(isa_string.c_str());
+ if (isa != kNone && isa != kRuntimeISA) {
+ action = Runtime::NativeBridgeAction::kInitialize;
+ }
+ }
+ Runtime::Current()->DidForkFromZygote(action);
}
static JNINativeMethod gMethods[] = {
NATIVE_METHOD(ZygoteHooks, nativePreFork, "()J"),
- NATIVE_METHOD(ZygoteHooks, nativePostForkChild, "(JI)V"),
+ NATIVE_METHOD(ZygoteHooks, nativePostForkChild, "(JILjava/lang/String;)V"),
};
void register_dalvik_system_ZygoteHooks(JNIEnv* env) {
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 5adb5d0..89ad505 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -428,7 +428,7 @@
return false;
}
} else {
- DidForkFromZygote();
+ DidForkFromZygote(NativeBridgeAction::kInitialize);
}
StartDaemonThreads();
@@ -506,9 +506,19 @@
#endif
}
-void Runtime::DidForkFromZygote() {
+void Runtime::DidForkFromZygote(NativeBridgeAction action) {
is_zygote_ = false;
+ switch (action) {
+ case NativeBridgeAction::kUnload:
+ android::UnloadNativeBridge();
+ break;
+
+ case NativeBridgeAction::kInitialize:
+ android::InitializeNativeBridge();
+ break;
+ }
+
// Create the thread pool.
heap_->CreateThreadPool();
@@ -833,8 +843,34 @@
self->ClearException();
// Look for a native bridge.
+ //
+ // The intended flow here is, in the case of a running system:
+ //
+ // Runtime::Init() (zygote):
+ // LoadNativeBridge -> dlopen from cmd line parameter.
+ // |
+ // V
+ // Runtime::Start() (zygote):
+ // No-op wrt native bridge.
+ // |
+ // | start app
+ // V
+ // DidForkFromZygote(action)
+ // action = kUnload -> dlclose native bridge.
+ // action = kInitialize -> initialize library
+ //
+ //
+ // The intended flow here is, in the case of a simple dalvikvm call:
+ //
+ // Runtime::Init():
+ // LoadNativeBridge -> dlopen from cmd line parameter.
+ // |
+ // V
+ // Runtime::Start():
+ // DidForkFromZygote(kInitialize) -> try to initialize any native bridge given.
+ // No-op wrt native bridge.
native_bridge_library_filename_ = options->native_bridge_library_filename_;
- android::SetupNativeBridge(native_bridge_library_filename_.c_str(), &native_bridge_art_callbacks_);
+ android::LoadNativeBridge(native_bridge_library_filename_.c_str(), &native_bridge_art_callbacks_);
VLOG(startup) << "Runtime::Setup native bridge library: "
<< (native_bridge_library_filename_.empty() ?
"(empty)" : native_bridge_library_filename_);
diff --git a/runtime/runtime.h b/runtime/runtime.h
index 632806f..a0993ca 100644
--- a/runtime/runtime.h
+++ b/runtime/runtime.h
@@ -393,9 +393,13 @@
void SetStatsEnabled(bool new_state);
+ enum class NativeBridgeAction { // private
+ kUnload,
+ kInitialize
+ };
void PreZygoteFork();
bool InitZygote();
- void DidForkFromZygote();
+ void DidForkFromZygote(NativeBridgeAction action);
const instrumentation::Instrumentation* GetInstrumentation() const {
return &instrumentation_;
diff --git a/test/036-finalizer/expected.txt b/test/036-finalizer/expected.txt
index a2a74fc..36fa5f8 100644
--- a/test/036-finalizer/expected.txt
+++ b/test/036-finalizer/expected.txt
@@ -11,3 +11,4 @@
sleep
reborn: [FinalizerTest message=nothing, finalized=false]
wimp: null
+Finalized 1024 / 1024
diff --git a/test/036-finalizer/src/Main.java b/test/036-finalizer/src/Main.java
index 328425f..390472d 100644
--- a/test/036-finalizer/src/Main.java
+++ b/test/036-finalizer/src/Main.java
@@ -120,6 +120,39 @@
System.out.println("reborn: " + FinalizerTest.mReborn);
System.out.println("wimp: " + wimpString(wimp));
+ // Test runFinalization with multiple objects.
+ runFinalizationTest();
+ }
+
+ static class FinalizeCounter {
+ private static Object finalizeLock = new Object();
+ private static volatile int finalizeCount = 0;
+ private int index;
+ static int getCount() {
+ return finalizeCount;
+ }
+ FinalizeCounter(int index) {
+ this.index = index;
+ }
+ protected void finalize() {
+ synchronized(finalizeLock) {
+ ++finalizeCount;
+ }
+ }
+ }
+
+ private static void runFinalizationTest() {
+ int count = 1024;
+ Object[] objs = new Object[count];
+ for (int i = 0; i < count; ++i) {
+ objs[i] = new FinalizeCounter(i);
+ }
+ for (int i = 0; i < count; ++i) {
+ objs[i] = null;
+ }
+ System.gc();
+ System.runFinalization();
+ System.out.println("Finalized " + FinalizeCounter.getCount() + " / " + count);
}
public static class FinalizerTest {
diff --git a/test/115-native-bridge/expected.txt b/test/115-native-bridge/expected.txt
index 5b41606..808d968 100644
--- a/test/115-native-bridge/expected.txt
+++ b/test/115-native-bridge/expected.txt
@@ -1,5 +1,5 @@
-Ready for native bridge tests.
Native bridge initialized.
+Ready for native bridge tests.
Checking for support.
Getting trampoline for JNI_OnLoad with shorty (null).
Test ART callbacks: all JNI function number is 9.
diff --git a/test/etc/host-run-test-jar b/test/etc/host-run-test-jar
index 54a0865..4485590 100755
--- a/test/etc/host-run-test-jar
+++ b/test/etc/host-run-test-jar
@@ -208,7 +208,16 @@
fi
cd $ANDROID_BUILD_TOP
-# If we are execing /bin/false we might not be on the same ISA as libsigchain.so
-# ld.so will helpfully warn us of this. Unfortunately this messes up our error
-# checking so we will just filter out the error with a grep.
-$mkdir_cmd && $prebuild_cmd && LD_PRELOAD=libsigchain.so $cmdline "$@" 2>&1 | grep -v -E "^ERROR: ld\.so: object '.+\.so' from LD_PRELOAD cannot be preloaded: ignored\.$"
+
+$mkdir_cmd || exit 1
+$prebuild_cmd || exit 2
+
+if [ "$GDB" = "y" ]; then
+ # When running under gdb, we cannot do piping and grepping...
+ LD_PRELOAD=libsigchain.so $cmdline "$@"
+else
+ # If we are execing /bin/false we might not be on the same ISA as libsigchain.so
+ # ld.so will helpfully warn us of this. Unfortunately this messes up our error
+ # checking so we will just filter out the error with a grep.
+ LD_PRELOAD=libsigchain.so $cmdline "$@" 2>&1 | grep -v -E "^ERROR: ld\.so: object '.+\.so' from LD_PRELOAD cannot be preloaded: ignored\.$"
+fi
\ No newline at end of file