diff options
39 files changed, 560 insertions, 317 deletions
diff --git a/build/Android.common_build.mk b/build/Android.common_build.mk index dde3cdb1d5..0235a308f8 100644 --- a/build/Android.common_build.mk +++ b/build/Android.common_build.mk @@ -363,11 +363,20 @@ ART_HOST_ASFLAGS += $(art_asflags) ifndef LIBART_IMG_TARGET_BASE_ADDRESS $(error LIBART_IMG_TARGET_BASE_ADDRESS unset) endif + +ART_TARGET_CFLAGS += $(art_cflags) -DART_TARGET \ + -DART_BASE_ADDRESS=$(LIBART_IMG_TARGET_BASE_ADDRESS) \ + +ifeq ($(ART_TARGET_LINUX),true) +# Setting ART_TARGET_LINUX to true compiles art/ assuming that the target device +# will be running linux rather than android. +ART_TARGET_CFLAGS += -DART_TARGET_LINUX +else # The ART_TARGET_ANDROID macro is passed to target builds, which check # against it instead of against __ANDROID__ (which is provided by target # toolchains). -ART_TARGET_CFLAGS += $(art_cflags) -DART_TARGET -DART_TARGET_ANDROID \ - -DART_BASE_ADDRESS=$(LIBART_IMG_TARGET_BASE_ADDRESS) \ +ART_TARGET_CFLAGS += -DART_TARGET_ANDROID +endif ART_TARGET_CFLAGS += $(art_target_cflags) ART_TARGET_ASFLAGS += $(art_asflags) diff --git a/compiler/driver/compiler_options.cc b/compiler/driver/compiler_options.cc index 1bd4c3ad80..f20dba34a6 100644 --- a/compiler/driver/compiler_options.cc +++ b/compiler/driver/compiler_options.cc @@ -21,7 +21,7 @@ namespace art { CompilerOptions::CompilerOptions() - : compiler_filter_(kDefaultCompilerFilter), + : compiler_filter_(CompilerFilter::kDefaultCompilerFilter), huge_method_threshold_(kDefaultHugeMethodThreshold), large_method_threshold_(kDefaultLargeMethodThreshold), small_method_threshold_(kDefaultSmallMethodThreshold), diff --git a/compiler/driver/compiler_options.h b/compiler/driver/compiler_options.h index c67ab6ef14..6bbd3c5a19 100644 --- a/compiler/driver/compiler_options.h +++ b/compiler/driver/compiler_options.h @@ -31,7 +31,6 @@ namespace art { class CompilerOptions FINAL { public: // Guide heuristics to determine whether to compile method if profile data not available. - static const CompilerFilter::Filter kDefaultCompilerFilter = CompilerFilter::kSpeed; static const size_t kDefaultHugeMethodThreshold = 10000; static const size_t kDefaultLargeMethodThreshold = 600; static const size_t kDefaultSmallMethodThreshold = 60; diff --git a/compiler/jit/jit_compiler.cc b/compiler/jit/jit_compiler.cc index c2d7ff7795..178533849b 100644 --- a/compiler/jit/jit_compiler.cc +++ b/compiler/jit/jit_compiler.cc @@ -88,7 +88,7 @@ NO_RETURN static void Usage(const char* fmt, ...) { JitCompiler::JitCompiler() { compiler_options_.reset(new CompilerOptions( - CompilerOptions::kDefaultCompilerFilter, + CompilerFilter::kDefaultCompilerFilter, CompilerOptions::kDefaultHugeMethodThreshold, CompilerOptions::kDefaultLargeMethodThreshold, CompilerOptions::kDefaultSmallMethodThreshold, diff --git a/profman/profman.cc b/profman/profman.cc index 3e632bce8b..b3454fa2e7 100644 --- a/profman/profman.cc +++ b/profman/profman.cc @@ -216,7 +216,11 @@ class ProfMan FINAL { } void LogCompletionTime() { - LOG(INFO) << "profman took " << PrettyDuration(NanoTime() - start_ns_); + static constexpr uint64_t kLogThresholdTime = MsToNs(100); // 100ms + uint64_t time_taken = NanoTime() - start_ns_; + if (time_taken > kLogThresholdTime) { + LOG(WARNING) << "profman took " << PrettyDuration(NanoTime() - start_ns_); + } } std::vector<std::string> profile_files_; diff --git a/runtime/common_runtime_test.cc b/runtime/common_runtime_test.cc index f58af5a8da..5bdb36cafc 100644 --- a/runtime/common_runtime_test.cc +++ b/runtime/common_runtime_test.cc @@ -418,26 +418,6 @@ void CommonRuntimeTestImpl::TearDown() { (*icu_cleanup_fn)(); Runtime::Current()->GetHeap()->VerifyHeap(); // Check for heap corruption after the test - - // Manually closing the JNI libraries. - // Runtime does not support repeatedly doing JNI->CreateVM, thus we need to manually clean up the - // dynamic linking loader so that gtests would not fail. - // Bug: 25785594 - if (runtime_->IsStarted()) { - { - // We retrieve the handle by calling dlopen on the library. To close it, we need to call - // dlclose twice, the first time to undo our dlopen and the second time to actually unload it. - // See man dlopen. - void* handle = dlopen("libjavacore.so", RTLD_LAZY); - dlclose(handle); - CHECK_EQ(0, dlclose(handle)); - } - { - void* handle = dlopen("libopenjdkd.so", RTLD_LAZY); - dlclose(handle); - CHECK_EQ(0, dlclose(handle)); - } - } } static std::string GetDexFileName(const std::string& jar_prefix, bool host) { diff --git a/runtime/compiler_filter.h b/runtime/compiler_filter.h index 6289d8a22c..e8d74dd9e8 100644 --- a/runtime/compiler_filter.h +++ b/runtime/compiler_filter.h @@ -44,6 +44,8 @@ class CompilerFilter FINAL { kEverything, // Compile everything capable of being compiled. }; + static const Filter kDefaultCompilerFilter = kSpeed; + // Returns true if an oat file with this compiler filter contains // compiled executable code. static bool IsCompilationEnabled(Filter filter); diff --git a/runtime/dex_file_verifier.cc b/runtime/dex_file_verifier.cc index 3df4e98c84..21ee4bd528 100644 --- a/runtime/dex_file_verifier.cc +++ b/runtime/dex_file_verifier.cc @@ -2358,7 +2358,8 @@ static bool CheckAtMostOneOfPublicProtectedPrivate(uint32_t flags) { static std::string GetStringOrError(const uint8_t* const begin, const DexFile::Header* const header, uint32_t string_idx) { - if (header->string_ids_size_ < string_idx) { + // The `string_idx` is not guaranteed to be valid yet. + if (header->string_ids_size_ <= string_idx) { return "(error)"; } @@ -2375,9 +2376,11 @@ static std::string GetStringOrError(const uint8_t* const begin, static std::string GetClassOrError(const uint8_t* const begin, const DexFile::Header* const header, uint32_t class_idx) { - if (header->type_ids_size_ < class_idx) { - return "(error)"; - } + // The `class_idx` is either `FieldId::class_idx_` or `MethodId::class_idx_` and + // it has already been checked in `DexFileVerifier::CheckClassDataItemField()` + // or `DexFileVerifier::CheckClassDataItemMethod()`, respectively, to match + // a valid defining class. + CHECK_LT(class_idx, header->type_ids_size_); const DexFile::TypeId* type_id = reinterpret_cast<const DexFile::TypeId*>(begin + header->type_ids_off_) + class_idx; @@ -2390,9 +2393,8 @@ static std::string GetClassOrError(const uint8_t* const begin, static std::string GetFieldDescriptionOrError(const uint8_t* const begin, const DexFile::Header* const header, uint32_t idx) { - if (header->field_ids_size_ < idx) { - return "(error)"; - } + // The `idx` has already been checked in `DexFileVerifier::CheckClassDataItemField()`. + CHECK_LT(idx, header->field_ids_size_); const DexFile::FieldId* field_id = reinterpret_cast<const DexFile::FieldId*>(begin + header->field_ids_off_) + idx; @@ -2408,9 +2410,8 @@ static std::string GetFieldDescriptionOrError(const uint8_t* const begin, static std::string GetMethodDescriptionOrError(const uint8_t* const begin, const DexFile::Header* const header, uint32_t idx) { - if (header->method_ids_size_ < idx) { - return "(error)"; - } + // The `idx` has already been checked in `DexFileVerifier::CheckClassDataItemMethod()`. + CHECK_LT(idx, header->method_ids_size_); const DexFile::MethodId* method_id = reinterpret_cast<const DexFile::MethodId*>(begin + header->method_ids_off_) + idx; diff --git a/runtime/dex_file_verifier_test.cc b/runtime/dex_file_verifier_test.cc index 344d186ad4..84f48daccb 100644 --- a/runtime/dex_file_verifier_test.cc +++ b/runtime/dex_file_verifier_test.cc @@ -57,7 +57,7 @@ static const uint8_t kBase64Map[256] = { 255, 255, 255, 255 }; -static inline uint8_t* DecodeBase64(const char* src, size_t* dst_size) { +static inline std::unique_ptr<uint8_t[]> DecodeBase64(const char* src, size_t* dst_size) { std::vector<uint8_t> tmp; uint32_t t = 0, y = 0; int g = 3; @@ -100,7 +100,7 @@ static inline uint8_t* DecodeBase64(const char* src, size_t* dst_size) { *dst_size = 0; } std::copy(tmp.begin(), tmp.end(), dst.get()); - return dst.release(); + return dst; } static void FixUpChecksum(uint8_t* dex_file) { @@ -113,25 +113,18 @@ static void FixUpChecksum(uint8_t* dex_file) { header->checksum_ = adler_checksum; } -// Custom deleter. Necessary to clean up the memory we use (to be able to mutate). -struct DexFileDeleter { - void operator()(DexFile* in) { - if (in != nullptr) { - delete[] in->Begin(); - delete in; - } - } -}; - -using DexFileUniquePtr = std::unique_ptr<DexFile, DexFileDeleter>; - class DexFileVerifierTest : public CommonRuntimeTest { protected: void VerifyModification(const char* dex_file_base64_content, const char* location, std::function<void(DexFile*)> f, const char* expected_error) { - DexFileUniquePtr dex_file(WrapAsDexFile(dex_file_base64_content)); + size_t length; + std::unique_ptr<uint8_t[]> dex_bytes = DecodeBase64(dex_file_base64_content, &length); + CHECK(dex_bytes != nullptr); + // Note: `dex_file` will be destroyed before `dex_bytes`. + std::unique_ptr<DexFile> dex_file( + new DexFile(dex_bytes.get(), length, "tmp", 0, nullptr, nullptr)); f(dex_file.get()); FixUpChecksum(const_cast<uint8_t*>(dex_file->Begin())); @@ -150,15 +143,6 @@ class DexFileVerifierTest : public CommonRuntimeTest { } } } - - private: - static DexFile* WrapAsDexFile(const char* dex_file_content_in_base_64) { - // Decode base64. - size_t length; - uint8_t* dex_bytes = DecodeBase64(dex_file_content_in_base_64, &length); - CHECK(dex_bytes != nullptr); - return new DexFile(dex_bytes, length, "tmp", 0, nullptr, nullptr); - } }; static std::unique_ptr<const DexFile> OpenDexFileBase64(const char* base64, @@ -290,7 +274,9 @@ static const char kMethodFlagsTestDex[] = // Find the method data for the first method with the given name (from class 0). Note: the pointer // is to the access flags, so that the caller doesn't have to handle the leb128-encoded method-index // delta. -static const uint8_t* FindMethodData(const DexFile* dex_file, const char* name) { +static const uint8_t* FindMethodData(const DexFile* dex_file, + const char* name, + /*out*/ uint32_t* method_idx = nullptr) { const DexFile::ClassDef& class_def = dex_file->GetClassDef(0); const uint8_t* class_data = dex_file->GetClassData(class_def); @@ -316,6 +302,9 @@ static const uint8_t* FindMethodData(const DexFile* dex_file, const char* name) const DexFile::StringId& string_id = dex_file->GetStringId(name_index); const char* str = dex_file->GetStringData(string_id); if (strcmp(name, str) == 0) { + if (method_idx != nullptr) { + *method_idx = method_index; + } DecodeUnsignedLeb128(&trailing); return trailing; } @@ -683,6 +672,22 @@ TEST_F(DexFileVerifierTest, MethodAccessFlagsIgnoredOK) { } } +TEST_F(DexFileVerifierTest, B28552165) { + // Regression test for bad error string retrieval in different situations. + // Using invalid access flags to trigger the error. + VerifyModification( + kMethodFlagsTestDex, + "b28552165", + [](DexFile* dex_file) { + OrMaskToMethodFlags(dex_file, "foo", kAccPublic | kAccProtected); + uint32_t method_idx; + FindMethodData(dex_file, "foo", &method_idx); + auto* method_id = const_cast<DexFile::MethodId*>(&dex_file->GetMethodId(method_idx)); + method_id->name_idx_ = dex_file->NumStringIds(); + }, + "Method may have only one of public/protected/private, LMethodFlags;.(error)"); +} + // Set of dex files for interface method tests. As it's not as easy to mutate method names, it's // just easier to break up bad cases. diff --git a/runtime/globals.h b/runtime/globals.h index e7ea6f3788..477cbdf5d4 100644 --- a/runtime/globals.h +++ b/runtime/globals.h @@ -51,11 +51,31 @@ static constexpr bool kIsDebugBuild = false; static constexpr bool kIsDebugBuild = true; #endif -// Whether or not this is a target (vs host) build. Useful in conditionals where ART_TARGET isn't. +// ART_TARGET - Defined for target builds of ART. +// ART_TARGET_LINUX - Defined for target Linux builds of ART. +// ART_TARGET_ANDROID - Defined for target Android builds of ART. +// Note: Either ART_TARGET_LINUX or ART_TARGET_ANDROID need to be set when ART_TARGET is set. +// Note: When ART_TARGET_LINUX is defined mem_map.h will not be using Ashmem for memory mappings +// (usually only available on Android kernels). #if defined(ART_TARGET) +// Useful in conditionals where ART_TARGET isn't. static constexpr bool kIsTargetBuild = true; +#if defined(ART_TARGET_LINUX) +static constexpr bool kIsTargetLinux = true; +#elif defined(ART_TARGET_ANDROID) +static constexpr bool kIsTargetLinux = false; +#else +#error "Either ART_TARGET_LINUX or ART_TARGET_ANDROID needs to be defined for target builds." +#endif #else static constexpr bool kIsTargetBuild = false; +#if defined(ART_TARGET_LINUX) +#error "ART_TARGET_LINUX defined for host build." +#elif defined(ART_TARGET_ANDROID) +#error "ART_TARGET_ANDROID defined for host build." +#else +static constexpr bool kIsTargetLinux = false; +#endif #endif // Garbage collector constants. diff --git a/runtime/interpreter/interpreter.cc b/runtime/interpreter/interpreter.cc index 81a396a925..6c630cc48f 100644 --- a/runtime/interpreter/interpreter.cc +++ b/runtime/interpreter/interpreter.cc @@ -515,8 +515,24 @@ void EnterInterpreterFromDeoptimize(Thread* self, // instruction, as it already executed. // TODO: should be tested more once b/17586779 is fixed. const Instruction* instr = Instruction::At(&code_item->insns_[dex_pc]); - DCHECK(instr->IsInvoke()); - new_dex_pc = dex_pc + instr->SizeInCodeUnits(); + if (instr->IsInvoke()) { + new_dex_pc = dex_pc + instr->SizeInCodeUnits(); + } else if (instr->Opcode() == Instruction::NEW_INSTANCE) { + // It's possible to deoptimize at a NEW_INSTANCE dex instruciton that's for a + // java string, which is turned into a call into StringFactory.newEmptyString(); + if (kIsDebugBuild) { + ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); + mirror::Class* klass = class_linker->ResolveType( + instr->VRegB_21c(), shadow_frame->GetMethod()); + DCHECK(klass->IsStringClass()); + } + // Skip the dex instruction since we essentially come back from an invocation. + new_dex_pc = dex_pc + instr->SizeInCodeUnits(); + } else { + DCHECK(false) << "Unexpected instruction opcode " << instr->Opcode() + << " at dex_pc " << dex_pc + << " of method: " << PrettyMethod(shadow_frame->GetMethod(), false); + } } else { // Nothing to do, the dex_pc is the one at which the code requested // the deoptimization. diff --git a/runtime/java_vm_ext.cc b/runtime/java_vm_ext.cc index 79c320309c..3de718b397 100644 --- a/runtime/java_vm_ext.cc +++ b/runtime/java_vm_ext.cc @@ -74,6 +74,10 @@ class SharedLibrary { if (self != nullptr) { self->GetJniEnv()->DeleteWeakGlobalRef(class_loader_); } + + if (!needs_native_bridge_) { + android::CloseNativeLibrary(handle_); + } } jweak GetClassLoader() const { @@ -271,8 +275,7 @@ class Libraries { REQUIRES(!Locks::jni_libraries_lock_) SHARED_REQUIRES(Locks::mutator_lock_) { ScopedObjectAccessUnchecked soa(Thread::Current()); - typedef void (*JNI_OnUnloadFn)(JavaVM*, void*); - std::vector<JNI_OnUnloadFn> unload_functions; + std::vector<SharedLibrary*> unload_libraries; { MutexLock mu(soa.Self(), *Locks::jni_libraries_lock_); for (auto it = libraries_.begin(); it != libraries_.end(); ) { @@ -283,15 +286,7 @@ class Libraries { // the native libraries of the boot class loader. if (class_loader != nullptr && soa.Self()->IsJWeakCleared(class_loader)) { - void* const sym = library->FindSymbol("JNI_OnUnload", nullptr); - if (sym == nullptr) { - VLOG(jni) << "[No JNI_OnUnload found in \"" << library->GetPath() << "\"]"; - } else { - VLOG(jni) << "[JNI_OnUnload found for \"" << library->GetPath() << "\"]"; - JNI_OnUnloadFn jni_on_unload = reinterpret_cast<JNI_OnUnloadFn>(sym); - unload_functions.push_back(jni_on_unload); - } - delete library; + unload_libraries.push_back(library); it = libraries_.erase(it); } else { ++it; @@ -299,9 +294,17 @@ class Libraries { } } // Do this without holding the jni libraries lock to prevent possible deadlocks. - for (JNI_OnUnloadFn fn : unload_functions) { - VLOG(jni) << "Calling JNI_OnUnload"; - (*fn)(soa.Vm(), nullptr); + typedef void (*JNI_OnUnloadFn)(JavaVM*, void*); + for (auto library : unload_libraries) { + void* const sym = library->FindSymbol("JNI_OnUnload", nullptr); + if (sym == nullptr) { + VLOG(jni) << "[No JNI_OnUnload found in \"" << library->GetPath() << "\"]"; + } else { + VLOG(jni) << "[JNI_OnUnload found for \"" << library->GetPath() << "\"]: Calling..."; + JNI_OnUnloadFn jni_on_unload = reinterpret_cast<JNI_OnUnloadFn>(sym); + jni_on_unload(soa.Vm(), nullptr); + } + delete library; } } diff --git a/runtime/mem_map.cc b/runtime/mem_map.cc index 5d89c21803..771f8ed290 100644 --- a/runtime/mem_map.cc +++ b/runtime/mem_map.cc @@ -302,8 +302,9 @@ MemMap* MemMap::MapAnonymous(const char* name, if (use_ashmem) { if (!kIsTargetBuild) { - // When not on Android ashmem is faked using files in /tmp. Ensure that such files won't - // fail due to ulimit restrictions. If they will then use a regular mmap. + // When not on Android (either host or assuming a linux target) ashmem is faked using + // files in /tmp. Ensure that such files won't fail due to ulimit restrictions. If they + // will then use a regular mmap. struct rlimit rlimit_fsize; CHECK_EQ(getrlimit(RLIMIT_FSIZE, &rlimit_fsize), 0); use_ashmem = (rlimit_fsize.rlim_cur == RLIM_INFINITY) || diff --git a/runtime/mem_map.h b/runtime/mem_map.h index 3eaf576845..597f0d46e1 100644 --- a/runtime/mem_map.h +++ b/runtime/mem_map.h @@ -68,7 +68,7 @@ class MemMap { bool low_4gb, bool reuse, std::string* error_msg, - bool use_ashmem = true); + bool use_ashmem = !kIsTargetLinux); // Create placeholder for a region allocated by direct call to mmap. // This is useful when we do not have control over the code calling mmap, @@ -172,7 +172,7 @@ class MemMap { const char* tail_name, int tail_prot, std::string* error_msg, - bool use_ashmem = true); + bool use_ashmem = !kIsTargetLinux); static bool CheckNoGaps(MemMap* begin_map, MemMap* end_map) REQUIRES(!Locks::mem_maps_lock_); diff --git a/runtime/oat_file_assistant.cc b/runtime/oat_file_assistant.cc index 3f95772b4f..a508e87c87 100644 --- a/runtime/oat_file_assistant.cc +++ b/runtime/oat_file_assistant.cc @@ -179,11 +179,38 @@ OatFileAssistant::DexOptNeeded OatFileAssistant::GetDexOptNeeded(CompilerFilter: return HasOriginalDexFiles() ? kDex2OatNeeded : kNoDexOptNeeded; } +// Figure out the currently specified compile filter option in the runtime. +// Returns true on success, false if the compiler filter is invalid, in which +// case error_msg describes the problem. +static bool GetRuntimeCompilerFilterOption(CompilerFilter::Filter* filter, + std::string* error_msg) { + CHECK(filter != nullptr); + CHECK(error_msg != nullptr); + + *filter = CompilerFilter::kDefaultCompilerFilter; + for (StringPiece option : Runtime::Current()->GetCompilerOptions()) { + if (option.starts_with("--compiler-filter=")) { + const char* compiler_filter_string = option.substr(strlen("--compiler-filter=")).data(); + if (!CompilerFilter::ParseCompilerFilter(compiler_filter_string, filter)) { + *error_msg = std::string("Unknown --compiler-filter value: ") + + std::string(compiler_filter_string); + return false; + } + } + } + return true; +} + OatFileAssistant::ResultOfAttemptToUpdate -OatFileAssistant::MakeUpToDate(CompilerFilter::Filter target, std::string* error_msg) { +OatFileAssistant::MakeUpToDate(std::string* error_msg) { + CompilerFilter::Filter target; + if (!GetRuntimeCompilerFilterOption(&target, error_msg)) { + return kUpdateNotAttempted; + } + switch (GetDexOptNeeded(target)) { case kNoDexOptNeeded: return kUpdateSucceeded; - case kDex2OatNeeded: return GenerateOatFile(target, error_msg); + case kDex2OatNeeded: return GenerateOatFile(error_msg); case kPatchOatNeeded: return RelocateOatFile(OdexFileName(), error_msg); case kSelfPatchOatNeeded: return RelocateOatFile(OatFileName(), error_msg); } @@ -634,7 +661,7 @@ OatFileAssistant::RelocateOatFile(const std::string* input_file, std::string* er } OatFileAssistant::ResultOfAttemptToUpdate -OatFileAssistant::GenerateOatFile(CompilerFilter::Filter target, std::string* error_msg) { +OatFileAssistant::GenerateOatFile(std::string* error_msg) { CHECK(error_msg != nullptr); Runtime* runtime = Runtime::Current(); @@ -678,7 +705,6 @@ OatFileAssistant::GenerateOatFile(CompilerFilter::Filter target, std::string* er args.push_back("--dex-file=" + dex_location_); args.push_back("--oat-fd=" + std::to_string(oat_file->Fd())); args.push_back("--oat-location=" + oat_file_name); - args.push_back("--compiler-filter=" + CompilerFilter::NameOfFilter(target)); if (!Dex2Oat(args, error_msg)) { // Manually delete the file. This ensures there is no garbage left over if diff --git a/runtime/oat_file_assistant.h b/runtime/oat_file_assistant.h index d3228deac7..85f4a47868 100644 --- a/runtime/oat_file_assistant.h +++ b/runtime/oat_file_assistant.h @@ -159,15 +159,12 @@ class OatFileAssistant { }; // Attempts to generate or relocate the oat file as needed to make it up to - // date with in a way that is at least as good as an oat file generated with - // the given compiler filter. - // Returns the result of attempting to update the code. + // date based on the current runtime and compiler options. // // If the result is not kUpdateSucceeded, the value of error_msg will be set // to a string describing why there was a failure or the update was not // attempted. error_msg must not be null. - ResultOfAttemptToUpdate MakeUpToDate(CompilerFilter::Filter target_compiler_filter, - std::string* error_msg); + ResultOfAttemptToUpdate MakeUpToDate(std::string* error_msg); // Returns an oat file that can be used for loading dex files. // Returns null if no suitable oat file was found. @@ -250,14 +247,15 @@ class OatFileAssistant { // attempted. error_msg must not be null. ResultOfAttemptToUpdate RelocateOatFile(const std::string* input_file, std::string* error_msg); - // Generate the oat file from the dex file using the given compiler filter. + // Generate the oat file from the dex file using the current runtime + // compiler options. // This does not check the current status before attempting to generate the // oat file. // // If the result is not kUpdateSucceeded, the value of error_msg will be set // to a string describing why there was a failure or the update was not // attempted. error_msg must not be null. - ResultOfAttemptToUpdate GenerateOatFile(CompilerFilter::Filter filter, std::string* error_msg); + ResultOfAttemptToUpdate GenerateOatFile(std::string* error_msg); // Executes dex2oat using the current runtime configuration overridden with // the given arguments. This does not check to see if dex2oat is enabled in diff --git a/runtime/oat_file_assistant_test.cc b/runtime/oat_file_assistant_test.cc index f50d1cb748..764b969eaa 100644 --- a/runtime/oat_file_assistant_test.cc +++ b/runtime/oat_file_assistant_test.cc @@ -453,8 +453,7 @@ TEST_F(OatFileAssistantTest, NoDexNoOat) { // Trying to make the oat file up to date should not fail or crash. std::string error_msg; - EXPECT_EQ(OatFileAssistant::kUpdateSucceeded, - oat_file_assistant.MakeUpToDate(CompilerFilter::kSpeed, &error_msg)); + EXPECT_EQ(OatFileAssistant::kUpdateSucceeded, oat_file_assistant.MakeUpToDate(&error_msg)); // Trying to get the best oat file should fail, but not crash. std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile(); @@ -705,8 +704,9 @@ TEST_F(OatFileAssistantTest, StrippedDexOdexNoOat) { // Make the oat file up to date. std::string error_msg; + Runtime::Current()->AddCompilerOption("--compiler-filter=speed"); ASSERT_EQ(OatFileAssistant::kUpdateSucceeded, - oat_file_assistant.MakeUpToDate(CompilerFilter::kSpeed, &error_msg)) << error_msg; + oat_file_assistant.MakeUpToDate(&error_msg)) << error_msg; EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded, oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed)); @@ -768,8 +768,9 @@ TEST_F(OatFileAssistantTest, StrippedDexOdexOat) { // Make the oat file up to date. std::string error_msg; + Runtime::Current()->AddCompilerOption("--compiler-filter=speed"); ASSERT_EQ(OatFileAssistant::kUpdateSucceeded, - oat_file_assistant.MakeUpToDate(CompilerFilter::kSpeed, &error_msg)) << error_msg; + oat_file_assistant.MakeUpToDate(&error_msg)) << error_msg; EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded, oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed)); @@ -825,8 +826,9 @@ TEST_F(OatFileAssistantTest, ResourceOnlyDex) { // Make the oat file up to date. This should have no effect. std::string error_msg; + Runtime::Current()->AddCompilerOption("--compiler-filter=speed"); EXPECT_EQ(OatFileAssistant::kUpdateSucceeded, - oat_file_assistant.MakeUpToDate(CompilerFilter::kSpeed, &error_msg)) << error_msg; + oat_file_assistant.MakeUpToDate(&error_msg)) << error_msg; EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded, oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed)); @@ -876,8 +878,9 @@ TEST_F(OatFileAssistantTest, SelfRelocation) { // Make the oat file up to date. std::string error_msg; + Runtime::Current()->AddCompilerOption("--compiler-filter=speed"); ASSERT_EQ(OatFileAssistant::kUpdateSucceeded, - oat_file_assistant.MakeUpToDate(CompilerFilter::kSpeed, &error_msg)) << error_msg; + oat_file_assistant.MakeUpToDate(&error_msg)) << error_msg; EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded, oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed)); @@ -920,8 +923,9 @@ TEST_F(OatFileAssistantTest, NoSelfRelocation) { // Make the oat file up to date. std::string error_msg; + Runtime::Current()->AddCompilerOption("--compiler-filter=speed"); ASSERT_EQ(OatFileAssistant::kUpdateSucceeded, - oat_file_assistant.MakeUpToDate(CompilerFilter::kSpeed, &error_msg)) << error_msg; + oat_file_assistant.MakeUpToDate(&error_msg)) << error_msg; EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded, oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed)); @@ -1100,8 +1104,9 @@ TEST_F(OatFileAssistantTest, LoadDexNoAlternateOat) { OatFileAssistant oat_file_assistant( dex_location.c_str(), oat_location.c_str(), kRuntimeISA, false, true); std::string error_msg; + Runtime::Current()->AddCompilerOption("--compiler-filter=speed"); ASSERT_EQ(OatFileAssistant::kUpdateSucceeded, - oat_file_assistant.MakeUpToDate(CompilerFilter::kSpeed, &error_msg)) << error_msg; + oat_file_assistant.MakeUpToDate(&error_msg)) << error_msg; std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile(); ASSERT_TRUE(oat_file.get() != nullptr); @@ -1131,8 +1136,9 @@ TEST_F(OatFileAssistantTest, LoadDexUnwriteableAlternateOat) { OatFileAssistant oat_file_assistant( dex_location.c_str(), oat_location.c_str(), kRuntimeISA, false, true); std::string error_msg; + Runtime::Current()->AddCompilerOption("--compiler-filter=speed"); ASSERT_EQ(OatFileAssistant::kUpdateNotAttempted, - oat_file_assistant.MakeUpToDate(CompilerFilter::kSpeed, &error_msg)); + oat_file_assistant.MakeUpToDate(&error_msg)); std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile(); ASSERT_TRUE(oat_file.get() == nullptr); @@ -1147,8 +1153,9 @@ TEST_F(OatFileAssistantTest, GenNoDex) { OatFileAssistant oat_file_assistant( dex_location.c_str(), oat_location.c_str(), kRuntimeISA, false, true); std::string error_msg; + Runtime::Current()->AddCompilerOption("--compiler-filter=speed"); EXPECT_EQ(OatFileAssistant::kUpdateNotAttempted, - oat_file_assistant.GenerateOatFile(CompilerFilter::kSpeed, &error_msg)); + oat_file_assistant.GenerateOatFile(&error_msg)); } // Turn an absolute path into a path relative to the current working @@ -1227,8 +1234,9 @@ TEST_F(OatFileAssistantTest, ShortDexLocation) { // Trying to make it up to date should have no effect. std::string error_msg; + Runtime::Current()->AddCompilerOption("--compiler-filter=speed"); EXPECT_EQ(OatFileAssistant::kUpdateSucceeded, - oat_file_assistant.MakeUpToDate(CompilerFilter::kSpeed, &error_msg)); + oat_file_assistant.MakeUpToDate(&error_msg)); EXPECT_TRUE(error_msg.empty()); } @@ -1368,6 +1376,34 @@ TEST_F(OatFileAssistantNoDex2OatTest, LoadMultiDexOdexNoOat) { EXPECT_EQ(2u, dex_files.size()); } +TEST_F(OatFileAssistantTest, RuntimeCompilerFilterOptionUsed) { + std::string dex_location = GetScratchDir() + "/RuntimeCompilerFilterOptionUsed.jar"; + Copy(GetDexSrc1(), dex_location); + + OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false, false); + + std::string error_msg; + Runtime::Current()->AddCompilerOption("--compiler-filter=interpret-only"); + EXPECT_EQ(OatFileAssistant::kUpdateSucceeded, + oat_file_assistant.MakeUpToDate(&error_msg)) << error_msg; + EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded, + oat_file_assistant.GetDexOptNeeded(CompilerFilter::kInterpretOnly)); + EXPECT_EQ(OatFileAssistant::kDex2OatNeeded, + oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed)); + + Runtime::Current()->AddCompilerOption("--compiler-filter=speed"); + EXPECT_EQ(OatFileAssistant::kUpdateSucceeded, + oat_file_assistant.MakeUpToDate(&error_msg)) << error_msg; + EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded, + oat_file_assistant.GetDexOptNeeded(CompilerFilter::kInterpretOnly)); + EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded, + oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed)); + + Runtime::Current()->AddCompilerOption("--compiler-filter=bogus"); + EXPECT_EQ(OatFileAssistant::kUpdateNotAttempted, + oat_file_assistant.MakeUpToDate(&error_msg)); +} + TEST(OatFileAssistantUtilsTest, DexFilenameToOdexFilename) { std::string error_msg; std::string odex_file; diff --git a/runtime/oat_file_manager.cc b/runtime/oat_file_manager.cc index 9ab0072ea9..bc01da4fc4 100644 --- a/runtime/oat_file_manager.cc +++ b/runtime/oat_file_manager.cc @@ -44,8 +44,6 @@ static constexpr bool kDuplicateClassesCheck = kIsDebugBuild; // If true, then we attempt to load the application image if it exists. static constexpr bool kEnableAppImage = true; -CompilerFilter::Filter OatFileManager::filter_ = CompilerFilter::Filter::kSpeed; - const OatFile* OatFileManager::RegisterOatFile(std::unique_ptr<const OatFile> oat_file) { WriterMutexLock mu(Thread::Current(), *Locks::oat_file_manager_lock_); DCHECK(oat_file != nullptr); @@ -341,9 +339,10 @@ std::vector<std::unique_ptr<const DexFile>> OatFileManager::OpenDexFilesFromOat( const OatFile* source_oat_file = nullptr; - // Update the oat file on disk if we can. This may fail, but that's okay. - // Best effort is all that matters here. - switch (oat_file_assistant.MakeUpToDate(filter_, /*out*/ &error_msg)) { + // Update the oat file on disk if we can, based on the --compiler-filter + // option derived from the current runtime options. + // This may fail, but that's okay. Best effort is all that matters here. + switch (oat_file_assistant.MakeUpToDate(/*out*/ &error_msg)) { case OatFileAssistant::kUpdateFailed: LOG(WARNING) << error_msg; break; diff --git a/runtime/oat_file_manager.h b/runtime/oat_file_manager.h index f98102e844..7017dfc6ec 100644 --- a/runtime/oat_file_manager.h +++ b/runtime/oat_file_manager.h @@ -25,7 +25,6 @@ #include "base/macros.h" #include "base/mutex.h" -#include "compiler_filter.h" #include "jni.h" namespace art { @@ -116,10 +115,6 @@ class OatFileManager { void DumpForSigQuit(std::ostream& os); - static void SetCompilerFilter(CompilerFilter::Filter filter) { - filter_ = filter; - } - private: // Check for duplicate class definitions of the given oat file against all open oat files. // Return true if there are any class definition collisions in the oat_file. @@ -133,9 +128,6 @@ class OatFileManager { std::unordered_map<std::string, size_t> oat_file_count_ GUARDED_BY(Locks::oat_file_count_lock_); bool have_non_pic_oat_file_; - // The compiler filter used for oat files loaded by the oat file manager. - static CompilerFilter::Filter filter_; - DISALLOW_COPY_AND_ASSIGN(OatFileManager); }; diff --git a/runtime/parsed_options.cc b/runtime/parsed_options.cc index b25a1bb90f..eac5b43ff2 100644 --- a/runtime/parsed_options.cc +++ b/runtime/parsed_options.cc @@ -292,9 +292,6 @@ std::unique_ptr<RuntimeParser> ParsedOptions::MakeParser(bool ignore_unrecognize .IntoKey(M::Experimental) .Define("-Xforce-nb-testing") .IntoKey(M::ForceNativeBridge) - .Define("-XOatFileManagerCompilerFilter:_") - .WithType<std::string>() - .IntoKey(M::OatFileManagerCompilerFilter) .Ignore({ "-ea", "-da", "-enableassertions", "-disableassertions", "--runtime-arg", "-esa", "-dsa", "-enablesystemassertions", "-disablesystemassertions", "-Xrs", "-Xint:_", diff --git a/runtime/runtime.cc b/runtime/runtime.cc index bb19cbd255..45ba7d0fc2 100644 --- a/runtime/runtime.cc +++ b/runtime/runtime.cc @@ -60,7 +60,6 @@ #include "base/unix_file/fd_file.h" #include "class_linker-inl.h" #include "compiler_callbacks.h" -#include "compiler_filter.h" #include "debugger.h" #include "elf_file.h" #include "entrypoints/runtime_asm_entrypoints.h" @@ -967,16 +966,6 @@ bool Runtime::Init(RuntimeArgumentMap&& runtime_options_in) { experimental_flags_ = runtime_options.GetOrDefault(Opt::Experimental); is_low_memory_mode_ = runtime_options.Exists(Opt::LowMemoryMode); - { - CompilerFilter::Filter filter; - std::string filter_str = runtime_options.GetOrDefault(Opt::OatFileManagerCompilerFilter); - if (!CompilerFilter::ParseCompilerFilter(filter_str.c_str(), &filter)) { - LOG(ERROR) << "Cannot parse compiler filter " << filter_str; - return false; - } - OatFileManager::SetCompilerFilter(filter); - } - XGcOption xgc_option = runtime_options.GetOrDefault(Opt::GcOption); heap_ = new gc::Heap(runtime_options.GetOrDefault(Opt::MemoryInitialSize), runtime_options.GetOrDefault(Opt::HeapGrowthLimit), diff --git a/runtime/runtime_options.def b/runtime/runtime_options.def index 2a96703109..6db0cb2cb6 100644 --- a/runtime/runtime_options.def +++ b/runtime/runtime_options.def @@ -134,6 +134,5 @@ RUNTIME_OPTIONS_KEY (void (*)(int32_t status), \ // We don't call abort(3) by default; see // Runtime::Abort. RUNTIME_OPTIONS_KEY (void (*)(), HookAbort, nullptr) -RUNTIME_OPTIONS_KEY (std::string, OatFileManagerCompilerFilter, "speed") #undef RUNTIME_OPTIONS_KEY diff --git a/test/004-JniTest/jni_test.cc b/test/004-JniTest/jni_test.cc index 2bdf8d1e71..8619ff7f3e 100644 --- a/test/004-JniTest/jni_test.cc +++ b/test/004-JniTest/jni_test.cc @@ -14,23 +14,22 @@ * limitations under the License. */ -#include <assert.h> #include <iostream> #include <pthread.h> #include <stdio.h> #include <vector> +#include "art_method-inl.h" +#include "base/logging.h" #include "jni.h" -#if defined(NDEBUG) -#error test code compiled without NDEBUG -#endif +namespace art { static JavaVM* jvm = nullptr; extern "C" JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void*) { - assert(vm != nullptr); - assert(jvm == nullptr); + CHECK(vm != nullptr); + CHECK(jvm == nullptr); jvm = vm; std::cout << "JNI_OnLoad called" << std::endl; return JNI_VERSION_1_6; @@ -39,24 +38,24 @@ extern "C" JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void*) { extern "C" JNIEXPORT void JNI_OnUnload(JavaVM*, void*) { // std::cout since LOG(INFO) adds extra stuff like pid. std::cout << "JNI_OnUnload called" << std::endl; - // Clear jvm for assert in test 004-JniTest. + // Clear jvm for CHECK in test 004-JniTest. jvm = nullptr; } static void* AttachHelper(void* arg) { - assert(jvm != nullptr); + CHECK(jvm != nullptr); JNIEnv* env = nullptr; JavaVMAttachArgs args = { JNI_VERSION_1_6, __FUNCTION__, nullptr }; int attach_result = jvm->AttachCurrentThread(&env, &args); - assert(attach_result == 0); + CHECK_EQ(attach_result, 0); typedef void (*Fn)(JNIEnv*); Fn fn = reinterpret_cast<Fn>(arg); fn(env); int detach_result = jvm->DetachCurrentThread(); - assert(detach_result == 0); + CHECK_EQ(detach_result, 0); return nullptr; } @@ -64,19 +63,19 @@ static void PthreadHelper(void (*fn)(JNIEnv*)) { pthread_t pthread; int pthread_create_result = pthread_create(&pthread, nullptr, AttachHelper, reinterpret_cast<void*>(fn)); - assert(pthread_create_result == 0); + CHECK_EQ(pthread_create_result, 0); int pthread_join_result = pthread_join(pthread, nullptr); - assert(pthread_join_result == 0); + CHECK_EQ(pthread_join_result, 0); } static void testFindClassOnAttachedNativeThread(JNIEnv* env) { jclass clazz = env->FindClass("Main"); - assert(clazz != nullptr); - assert(!env->ExceptionCheck()); + CHECK(clazz != nullptr); + CHECK(!env->ExceptionCheck()); jobjectArray array = env->NewObjectArray(0, clazz, nullptr); - assert(array != nullptr); - assert(!env->ExceptionCheck()); + CHECK(array != nullptr); + CHECK(!env->ExceptionCheck()); } // http://b/10994325 @@ -86,12 +85,12 @@ extern "C" JNIEXPORT void JNICALL Java_Main_testFindClassOnAttachedNativeThread( static void testFindFieldOnAttachedNativeThread(JNIEnv* env) { jclass clazz = env->FindClass("Main"); - assert(clazz != nullptr); - assert(!env->ExceptionCheck()); + CHECK(clazz != nullptr); + CHECK(!env->ExceptionCheck()); jfieldID field = env->GetStaticFieldID(clazz, "testFindFieldOnAttachedNativeThreadField", "Z"); - assert(field != nullptr); - assert(!env->ExceptionCheck()); + CHECK(field != nullptr); + CHECK(!env->ExceptionCheck()); env->SetStaticBooleanField(clazz, field, JNI_TRUE); } @@ -103,38 +102,38 @@ extern "C" JNIEXPORT void JNICALL Java_Main_testFindFieldOnAttachedNativeThreadN static void testReflectFieldGetFromAttachedNativeThread(JNIEnv* env) { jclass clazz = env->FindClass("Main"); - assert(clazz != nullptr); - assert(!env->ExceptionCheck()); + CHECK(clazz != nullptr); + CHECK(!env->ExceptionCheck()); jclass class_clazz = env->FindClass("java/lang/Class"); - assert(class_clazz != nullptr); - assert(!env->ExceptionCheck()); + CHECK(class_clazz != nullptr); + CHECK(!env->ExceptionCheck()); jmethodID getFieldMetodId = env->GetMethodID(class_clazz, "getField", "(Ljava/lang/String;)Ljava/lang/reflect/Field;"); - assert(getFieldMetodId != nullptr); - assert(!env->ExceptionCheck()); + CHECK(getFieldMetodId != nullptr); + CHECK(!env->ExceptionCheck()); jstring field_name = env->NewStringUTF("testReflectFieldGetFromAttachedNativeThreadField"); - assert(field_name != nullptr); - assert(!env->ExceptionCheck()); + CHECK(field_name != nullptr); + CHECK(!env->ExceptionCheck()); jobject field = env->CallObjectMethod(clazz, getFieldMetodId, field_name); - assert(field != nullptr); - assert(!env->ExceptionCheck()); + CHECK(field != nullptr); + CHECK(!env->ExceptionCheck()); jclass field_clazz = env->FindClass("java/lang/reflect/Field"); - assert(field_clazz != nullptr); - assert(!env->ExceptionCheck()); + CHECK(field_clazz != nullptr); + CHECK(!env->ExceptionCheck()); jmethodID getBooleanMetodId = env->GetMethodID(field_clazz, "getBoolean", "(Ljava/lang/Object;)Z"); - assert(getBooleanMetodId != nullptr); - assert(!env->ExceptionCheck()); + CHECK(getBooleanMetodId != nullptr); + CHECK(!env->ExceptionCheck()); jboolean value = env->CallBooleanMethod(field, getBooleanMetodId, /* ignored */ clazz); - assert(value == false); - assert(!env->ExceptionCheck()); + CHECK(value == false); + CHECK(!env->ExceptionCheck()); } // http://b/15539150 @@ -148,22 +147,22 @@ extern "C" JNIEXPORT void JNICALL Java_Main_testReflectFieldGetFromAttachedNativ extern "C" JNIEXPORT void JNICALL Java_Main_testCallStaticVoidMethodOnSubClassNative(JNIEnv* env, jclass) { jclass super_class = env->FindClass("Main$testCallStaticVoidMethodOnSubClass_SuperClass"); - assert(super_class != nullptr); + CHECK(super_class != nullptr); jmethodID execute = env->GetStaticMethodID(super_class, "execute", "()V"); - assert(execute != nullptr); + CHECK(execute != nullptr); jclass sub_class = env->FindClass("Main$testCallStaticVoidMethodOnSubClass_SubClass"); - assert(sub_class != nullptr); + CHECK(sub_class != nullptr); env->CallStaticVoidMethod(sub_class, execute); } extern "C" JNIEXPORT jobject JNICALL Java_Main_testGetMirandaMethodNative(JNIEnv* env, jclass) { jclass abstract_class = env->FindClass("Main$testGetMirandaMethod_MirandaAbstract"); - assert(abstract_class != nullptr); + CHECK(abstract_class != nullptr); jmethodID miranda_method = env->GetMethodID(abstract_class, "inInterface", "()Z"); - assert(miranda_method != nullptr); + CHECK(miranda_method != nullptr); return env->ToReflectedMethod(abstract_class, miranda_method, JNI_FALSE); } @@ -171,11 +170,11 @@ extern "C" JNIEXPORT jobject JNICALL Java_Main_testGetMirandaMethodNative(JNIEnv extern "C" void JNICALL Java_Main_testZeroLengthByteBuffers(JNIEnv* env, jclass) { std::vector<uint8_t> buffer(1); jobject byte_buffer = env->NewDirectByteBuffer(&buffer[0], 0); - assert(byte_buffer != nullptr); - assert(!env->ExceptionCheck()); + CHECK(byte_buffer != nullptr); + CHECK(!env->ExceptionCheck()); - assert(env->GetDirectBufferAddress(byte_buffer) == &buffer[0]); - assert(env->GetDirectBufferCapacity(byte_buffer) == 0); + CHECK_EQ(env->GetDirectBufferAddress(byte_buffer), &buffer[0]); + CHECK_EQ(env->GetDirectBufferCapacity(byte_buffer), 0); } constexpr size_t kByteReturnSize = 7; @@ -185,18 +184,18 @@ extern "C" jbyte JNICALL Java_Main_byteMethod(JNIEnv*, jclass, jbyte b1, jbyte b jbyte b3, jbyte b4, jbyte b5, jbyte b6, jbyte b7, jbyte b8, jbyte b9, jbyte b10) { // We use b1 to drive the output. - assert(b2 == 2); - assert(b3 == -3); - assert(b4 == 4); - assert(b5 == -5); - assert(b6 == 6); - assert(b7 == -7); - assert(b8 == 8); - assert(b9 == -9); - assert(b10 == 10); - - assert(0 <= b1); - assert(b1 < static_cast<jbyte>(kByteReturnSize)); + CHECK_EQ(b2, 2); + CHECK_EQ(b3, -3); + CHECK_EQ(b4, 4); + CHECK_EQ(b5, -5); + CHECK_EQ(b6, 6); + CHECK_EQ(b7, -7); + CHECK_EQ(b8, 8); + CHECK_EQ(b9, -9); + CHECK_EQ(b10, 10); + + CHECK_LE(0, b1); + CHECK_LT(b1, static_cast<jbyte>(kByteReturnSize)); return byte_returns[b1]; } @@ -210,18 +209,18 @@ extern "C" jshort JNICALL Java_Main_shortMethod(JNIEnv*, jclass, jshort s1, jsho jshort s3, jshort s4, jshort s5, jshort s6, jshort s7, jshort s8, jshort s9, jshort s10) { // We use s1 to drive the output. - assert(s2 == 2); - assert(s3 == -3); - assert(s4 == 4); - assert(s5 == -5); - assert(s6 == 6); - assert(s7 == -7); - assert(s8 == 8); - assert(s9 == -9); - assert(s10 == 10); - - assert(0 <= s1); - assert(s1 < static_cast<jshort>(kShortReturnSize)); + CHECK_EQ(s2, 2); + CHECK_EQ(s3, -3); + CHECK_EQ(s4, 4); + CHECK_EQ(s5, -5); + CHECK_EQ(s6, 6); + CHECK_EQ(s7, -7); + CHECK_EQ(s8, 8); + CHECK_EQ(s9, -9); + CHECK_EQ(s10, 10); + + CHECK_LE(0, s1); + CHECK_LT(s1, static_cast<jshort>(kShortReturnSize)); return short_returns[s1]; } @@ -231,17 +230,17 @@ extern "C" jboolean JNICALL Java_Main_booleanMethod(JNIEnv*, jclass, jboolean b1 jboolean b5, jboolean b6, jboolean b7, jboolean b8, jboolean b9, jboolean b10) { // We use b1 to drive the output. - assert(b2 == JNI_TRUE); - assert(b3 == JNI_FALSE); - assert(b4 == JNI_TRUE); - assert(b5 == JNI_FALSE); - assert(b6 == JNI_TRUE); - assert(b7 == JNI_FALSE); - assert(b8 == JNI_TRUE); - assert(b9 == JNI_FALSE); - assert(b10 == JNI_TRUE); - - assert(b1 == JNI_TRUE || b1 == JNI_FALSE); + CHECK_EQ(b2, JNI_TRUE); + CHECK_EQ(b3, JNI_FALSE); + CHECK_EQ(b4, JNI_TRUE); + CHECK_EQ(b5, JNI_FALSE); + CHECK_EQ(b6, JNI_TRUE); + CHECK_EQ(b7, JNI_FALSE); + CHECK_EQ(b8, JNI_TRUE); + CHECK_EQ(b9, JNI_FALSE); + CHECK_EQ(b10, JNI_TRUE); + + CHECK(b1 == JNI_TRUE || b1 == JNI_FALSE); return b1; } @@ -252,17 +251,17 @@ extern "C" jchar JNICALL Java_Main_charMethod(JNIEnv*, jclass, jchar c1, jchar c jchar c3, jchar c4, jchar c5, jchar c6, jchar c7, jchar c8, jchar c9, jchar c10) { // We use c1 to drive the output. - assert(c2 == 'a'); - assert(c3 == 'b'); - assert(c4 == 'c'); - assert(c5 == '0'); - assert(c6 == '1'); - assert(c7 == '2'); - assert(c8 == 1234); - assert(c9 == 2345); - assert(c10 == 3456); - - assert(c1 < static_cast<jchar>(kCharReturnSize)); + CHECK_EQ(c2, 'a'); + CHECK_EQ(c3, 'b'); + CHECK_EQ(c4, 'c'); + CHECK_EQ(c5, '0'); + CHECK_EQ(c6, '1'); + CHECK_EQ(c7, '2'); + CHECK_EQ(c8, 1234); + CHECK_EQ(c9, 2345); + CHECK_EQ(c10, 3456); + + CHECK_LT(c1, static_cast<jchar>(kCharReturnSize)); return char_returns[c1]; } @@ -281,39 +280,39 @@ static void testShallowGetCallingClassLoader(JNIEnv* env) { // Test direct call. { jclass vmstack_clazz = env->FindClass("dalvik/system/VMStack"); - assert(vmstack_clazz != nullptr); - assert(!env->ExceptionCheck()); + CHECK(vmstack_clazz != nullptr); + CHECK(!env->ExceptionCheck()); jmethodID getCallingClassLoaderMethodId = env->GetStaticMethodID(vmstack_clazz, "getCallingClassLoader", "()Ljava/lang/ClassLoader;"); - assert(getCallingClassLoaderMethodId != nullptr); - assert(!env->ExceptionCheck()); + CHECK(getCallingClassLoaderMethodId != nullptr); + CHECK(!env->ExceptionCheck()); jobject class_loader = env->CallStaticObjectMethod(vmstack_clazz, getCallingClassLoaderMethodId); - assert(class_loader == nullptr); - assert(!env->ExceptionCheck()); + CHECK(class_loader == nullptr); + CHECK(!env->ExceptionCheck()); } // Test one-level call. Use System.loadLibrary(). { jclass system_clazz = env->FindClass("java/lang/System"); - assert(system_clazz != nullptr); - assert(!env->ExceptionCheck()); + CHECK(system_clazz != nullptr); + CHECK(!env->ExceptionCheck()); jmethodID loadLibraryMethodId = env->GetStaticMethodID(system_clazz, "loadLibrary", "(Ljava/lang/String;)V"); - assert(loadLibraryMethodId != nullptr); - assert(!env->ExceptionCheck()); + CHECK(loadLibraryMethodId != nullptr); + CHECK(!env->ExceptionCheck()); // Create a string object. jobject library_string = env->NewStringUTF("non_existing_library"); - assert(library_string != nullptr); - assert(!env->ExceptionCheck()); + CHECK(library_string != nullptr); + CHECK(!env->ExceptionCheck()); env->CallStaticVoidMethod(system_clazz, loadLibraryMethodId, library_string); - assert(env->ExceptionCheck()); + CHECK(env->ExceptionCheck()); // We expect UnsatisfiedLinkError. jthrowable thrown = env->ExceptionOccurred(); @@ -321,7 +320,7 @@ static void testShallowGetCallingClassLoader(JNIEnv* env) { jclass unsatisfied_link_error_clazz = env->FindClass("java/lang/UnsatisfiedLinkError"); jclass thrown_class = env->GetObjectClass(thrown); - assert(env->IsSameObject(unsatisfied_link_error_clazz, thrown_class)); + CHECK(env->IsSameObject(unsatisfied_link_error_clazz, thrown_class)); } } @@ -333,31 +332,31 @@ extern "C" JNIEXPORT void JNICALL Java_Main_nativeTestShallowGetCallingClassLoad static void testShallowGetStackClass2(JNIEnv* env) { jclass vmstack_clazz = env->FindClass("dalvik/system/VMStack"); - assert(vmstack_clazz != nullptr); - assert(!env->ExceptionCheck()); + CHECK(vmstack_clazz != nullptr); + CHECK(!env->ExceptionCheck()); // Test direct call. { jmethodID getStackClass2MethodId = env->GetStaticMethodID(vmstack_clazz, "getStackClass2", "()Ljava/lang/Class;"); - assert(getStackClass2MethodId != nullptr); - assert(!env->ExceptionCheck()); + CHECK(getStackClass2MethodId != nullptr); + CHECK(!env->ExceptionCheck()); jobject caller_class = env->CallStaticObjectMethod(vmstack_clazz, getStackClass2MethodId); - assert(caller_class == nullptr); - assert(!env->ExceptionCheck()); + CHECK(caller_class == nullptr); + CHECK(!env->ExceptionCheck()); } // Test one-level call. Use VMStack.getStackClass1(). { jmethodID getStackClass1MethodId = env->GetStaticMethodID(vmstack_clazz, "getStackClass1", "()Ljava/lang/Class;"); - assert(getStackClass1MethodId != nullptr); - assert(!env->ExceptionCheck()); + CHECK(getStackClass1MethodId != nullptr); + CHECK(!env->ExceptionCheck()); jobject caller_class = env->CallStaticObjectMethod(vmstack_clazz, getStackClass1MethodId); - assert(caller_class == nullptr); - assert(!env->ExceptionCheck()); + CHECK(caller_class == nullptr); + CHECK(!env->ExceptionCheck()); } // For better testing we would need to compile against libcore and have a two-deep stack @@ -416,8 +415,8 @@ class JniCallNonvirtualVoidMethodTest { env_->ExceptionDescribe(); env_->FatalError(__FUNCTION__); } - assert(!env_->ExceptionCheck()); - assert(c != nullptr); + CHECK(!env_->ExceptionCheck()); + CHECK(c != nullptr); return c; } @@ -429,7 +428,7 @@ class JniCallNonvirtualVoidMethodTest { env_->ExceptionDescribe(); env_->FatalError(__FUNCTION__); } - assert(m != nullptr); + CHECK(m != nullptr); return m; } @@ -439,7 +438,7 @@ class JniCallNonvirtualVoidMethodTest { env_->ExceptionDescribe(); env_->FatalError(__FUNCTION__); } - assert(o != nullptr); + CHECK(o != nullptr); return o; } @@ -467,7 +466,7 @@ class JniCallNonvirtualVoidMethodTest { env_->ExceptionDescribe(); env_->FatalError(__FUNCTION__); } - assert(m != nullptr); + CHECK(m != nullptr); return m; } @@ -508,21 +507,21 @@ class JniCallNonvirtualVoidMethodTest { jobject sub_super = CallConstructor(sub_, super_constructor_); jobject sub_sub = CallConstructor(sub_, sub_constructor_); - assert(env_->IsInstanceOf(super_super, super_)); - assert(!env_->IsInstanceOf(super_super, sub_)); + CHECK(env_->IsInstanceOf(super_super, super_)); + CHECK(!env_->IsInstanceOf(super_super, sub_)); // Note that even though we called (and ran) the subclass // constructor, we are not the subclass. - assert(env_->IsInstanceOf(super_sub, super_)); - assert(!env_->IsInstanceOf(super_sub, sub_)); + CHECK(env_->IsInstanceOf(super_sub, super_)); + CHECK(!env_->IsInstanceOf(super_sub, sub_)); // Note that even though we called the superclass constructor, we // are still the subclass. - assert(env_->IsInstanceOf(sub_super, super_)); - assert(env_->IsInstanceOf(sub_super, sub_)); + CHECK(env_->IsInstanceOf(sub_super, super_)); + CHECK(env_->IsInstanceOf(sub_super, sub_)); - assert(env_->IsInstanceOf(sub_sub, super_)); - assert(env_->IsInstanceOf(sub_sub, sub_)); + CHECK(env_->IsInstanceOf(sub_sub, super_)); + CHECK(env_->IsInstanceOf(sub_sub, sub_)); } void TestnonstaticCallNonvirtualMethod(bool super_object, bool super_class, bool super_method, const char* test_case) { @@ -542,8 +541,8 @@ class JniCallNonvirtualVoidMethodTest { CallMethod(o, c, m, true, test_case); jboolean super_field = GetBooleanField(o, super_field_); jboolean sub_field = GetBooleanField(o, sub_field_); - assert(super_field == super_method); - assert(sub_field != super_method); + CHECK_EQ(super_field, super_method); + CHECK_NE(sub_field, super_method); } void TestnonstaticCallNonvirtualMethod() { @@ -565,20 +564,20 @@ extern "C" void JNICALL Java_Main_testCallNonvirtual(JNIEnv* env, jclass) { extern "C" JNIEXPORT void JNICALL Java_Main_testNewStringObject(JNIEnv* env, jclass) { jclass c = env->FindClass("java/lang/String"); - assert(c != nullptr); + CHECK(c != nullptr); jmethodID mid1 = env->GetMethodID(c, "<init>", "()V"); - assert(mid1 != nullptr); - assert(!env->ExceptionCheck()); + CHECK(mid1 != nullptr); + CHECK(!env->ExceptionCheck()); jmethodID mid2 = env->GetMethodID(c, "<init>", "([B)V"); - assert(mid2 != nullptr); - assert(!env->ExceptionCheck()); + CHECK(mid2 != nullptr); + CHECK(!env->ExceptionCheck()); jmethodID mid3 = env->GetMethodID(c, "<init>", "([C)V"); - assert(mid3 != nullptr); - assert(!env->ExceptionCheck()); + CHECK(mid3 != nullptr); + CHECK(!env->ExceptionCheck()); jmethodID mid4 = env->GetMethodID(c, "<init>", "(Ljava/lang/String;)V"); - assert(mid4 != nullptr); - assert(!env->ExceptionCheck()); + CHECK(mid4 != nullptr); + CHECK(!env->ExceptionCheck()); const char* test_array = "Test"; int byte_array_length = strlen(test_array); @@ -587,22 +586,22 @@ extern "C" JNIEXPORT void JNICALL Java_Main_testNewStringObject(JNIEnv* env, jcl // Test NewObject jstring s = reinterpret_cast<jstring>(env->NewObject(c, mid2, byte_array)); - assert(s != nullptr); - assert(env->GetStringLength(s) == byte_array_length); - assert(env->GetStringUTFLength(s) == byte_array_length); + CHECK(s != nullptr); + CHECK_EQ(env->GetStringLength(s), byte_array_length); + CHECK_EQ(env->GetStringUTFLength(s), byte_array_length); const char* chars = env->GetStringUTFChars(s, nullptr); - assert(strcmp(test_array, chars) == 0); + CHECK_EQ(strcmp(test_array, chars), 0); env->ReleaseStringUTFChars(s, chars); // Test AllocObject and Call(Nonvirtual)VoidMethod jstring s1 = reinterpret_cast<jstring>(env->AllocObject(c)); - assert(s1 != nullptr); + CHECK(s1 != nullptr); jstring s2 = reinterpret_cast<jstring>(env->AllocObject(c)); - assert(s2 != nullptr); + CHECK(s2 != nullptr); jstring s3 = reinterpret_cast<jstring>(env->AllocObject(c)); - assert(s3 != nullptr); + CHECK(s3 != nullptr); jstring s4 = reinterpret_cast<jstring>(env->AllocObject(c)); - assert(s4 != nullptr); + CHECK(s4 != nullptr); jcharArray char_array = env->NewCharArray(5); jstring string_arg = env->NewStringUTF("helloworld"); @@ -621,18 +620,18 @@ extern "C" JNIEXPORT void JNICALL Java_Main_testNewStringObject(JNIEnv* env, jcl // Test with global and weak global references jstring s5 = reinterpret_cast<jstring>(env->AllocObject(c)); - assert(s5 != nullptr); + CHECK(s5 != nullptr); s5 = reinterpret_cast<jstring>(env->NewGlobalRef(s5)); jstring s6 = reinterpret_cast<jstring>(env->AllocObject(c)); - assert(s6 != nullptr); + CHECK(s6 != nullptr); s6 = reinterpret_cast<jstring>(env->NewWeakGlobalRef(s6)); env->CallVoidMethod(s5, mid1); env->CallNonvirtualVoidMethod(s6, c, mid2, byte_array); - assert(env->GetStringLength(s5) == 0); - assert(env->GetStringLength(s6) == byte_array_length); + CHECK_EQ(env->GetStringLength(s5), 0); + CHECK_EQ(env->GetStringLength(s6), byte_array_length); const char* chars6 = env->GetStringUTFChars(s6, nullptr); - assert(strcmp(test_array, chars6) == 0); + CHECK_EQ(strcmp(test_array, chars6), 0); env->ReleaseStringUTFChars(s6, chars6); } @@ -664,8 +663,8 @@ class JniCallDefaultMethodsTest { public: explicit JniCallDefaultMethodsTest(JNIEnv* env) : env_(env), concrete_class_(env_->FindClass("ConcreteClass")) { - assert(!env_->ExceptionCheck()); - assert(concrete_class_ != nullptr); + CHECK(!env_->ExceptionCheck()); + CHECK(concrete_class_ != nullptr); } void Test() { @@ -688,14 +687,14 @@ class JniCallDefaultMethodsTest { void TestCalls(const char* declaring_class, std::vector<const char*> methods) { jmethodID new_method = env_->GetMethodID(concrete_class_, "<init>", "()V"); jobject obj = env_->NewObject(concrete_class_, new_method); - assert(!env_->ExceptionCheck()); - assert(obj != nullptr); + CHECK(!env_->ExceptionCheck()); + CHECK(obj != nullptr); jclass decl_class = env_->FindClass(declaring_class); - assert(!env_->ExceptionCheck()); - assert(decl_class != nullptr); + CHECK(!env_->ExceptionCheck()); + CHECK(decl_class != nullptr); for (const char* method : methods) { jmethodID method_id = env_->GetMethodID(decl_class, method, "()V"); - assert(!env_->ExceptionCheck()); + CHECK(!env_->ExceptionCheck()); printf("Calling method %s->%s on object of type ConcreteClass\n", declaring_class, method); env_->CallVoidMethod(obj, method_id); if (env_->ExceptionCheck()) { @@ -704,10 +703,10 @@ class JniCallDefaultMethodsTest { jmethodID to_string = env_->GetMethodID( env_->FindClass("java/lang/Object"), "toString", "()Ljava/lang/String;"); jstring exception_string = (jstring) env_->CallObjectMethod(thrown, to_string); - assert(!env_->ExceptionCheck()); + CHECK(!env_->ExceptionCheck()); const char* exception_string_utf8 = env_->GetStringUTFChars(exception_string, nullptr); - assert(!env_->ExceptionCheck()); - assert(exception_string_utf8 != nullptr); + CHECK(!env_->ExceptionCheck()); + CHECK(exception_string_utf8 != nullptr); printf("EXCEPTION OCCURED: %s\n", exception_string_utf8); env_->ReleaseStringUTFChars(exception_string, exception_string_utf8); } @@ -724,12 +723,12 @@ extern "C" JNIEXPORT void JNICALL Java_Main_testCallDefaultMethods(JNIEnv* env) static void InvokeSpecificMethod(JNIEnv* env, jobject obj, const char* method) { jclass lambda_class = env->FindClass("LambdaInterface"); - assert(!env->ExceptionCheck()); - assert(lambda_class != nullptr); + CHECK(!env->ExceptionCheck()); + CHECK(lambda_class != nullptr); jmethodID method_id = env->GetMethodID(lambda_class, method, "()V"); - assert(!env->ExceptionCheck()); + CHECK(!env->ExceptionCheck()); env->CallVoidMethod(obj, method_id); - assert(!env->ExceptionCheck()); + CHECK(!env->ExceptionCheck()); } extern "C" JNIEXPORT void JNICALL Java_Main_testInvokeLambdaDefaultMethod( @@ -740,3 +739,6 @@ extern "C" JNIEXPORT void JNICALL Java_Main_testInvokeLambdaDefaultMethod( extern "C" JNIEXPORT void JNICALL Java_Main_testInvokeLambdaMethod(JNIEnv* e, jclass, jobject l) { InvokeSpecificMethod(e, l, "sayHi"); } + +} // namespace art + diff --git a/test/004-ReferenceMap/stack_walk_refmap_jni.cc b/test/004-ReferenceMap/stack_walk_refmap_jni.cc index 284e5544fb..5304590ad0 100644 --- a/test/004-ReferenceMap/stack_walk_refmap_jni.cc +++ b/test/004-ReferenceMap/stack_walk_refmap_jni.cc @@ -14,6 +14,7 @@ * limitations under the License. */ +#include "art_method-inl.h" #include "check_reference_map_visitor.h" #include "jni.h" diff --git a/test/004-StackWalk/stack_walk_jni.cc b/test/004-StackWalk/stack_walk_jni.cc index 51bb68f24a..420224dd21 100644 --- a/test/004-StackWalk/stack_walk_jni.cc +++ b/test/004-StackWalk/stack_walk_jni.cc @@ -14,6 +14,7 @@ * limitations under the License. */ +#include "art_method-inl.h" #include "check_reference_map_visitor.h" #include "jni.h" diff --git a/test/136-daemon-jni-shutdown/daemon_jni_shutdown.cc b/test/136-daemon-jni-shutdown/daemon_jni_shutdown.cc index 54879fbad9..c9110a905d 100644 --- a/test/136-daemon-jni-shutdown/daemon_jni_shutdown.cc +++ b/test/136-daemon-jni-shutdown/daemon_jni_shutdown.cc @@ -14,6 +14,7 @@ * limitations under the License. */ +#include <dlfcn.h> #include <iostream> #include "base/casts.h" @@ -45,6 +46,10 @@ extern "C" JNIEXPORT void JNICALL Java_Main_destroyJavaVMAndExit(JNIEnv* env, jc self->SetTopOfShadowStack(nullptr); JavaVM* vm = down_cast<JNIEnvExt*>(env)->vm; vm->DetachCurrentThread(); + // Open ourself again to make sure the native library does not get unloaded from + // underneath us due to DestroyJavaVM. b/28406866 + void* handle = dlopen(kIsDebugBuild ? "libarttestd.so" : "libarttest.so", RTLD_NOW); + CHECK(handle != nullptr); vm->DestroyJavaVM(); vm_was_shutdown.store(true); // Give threads some time to get stuck in ExceptionCheck. diff --git a/test/566-polymorphic-inlining/src/Main.java b/test/566-polymorphic-inlining/src/Main.java index 286f0d996e..a59ce5b344 100644 --- a/test/566-polymorphic-inlining/src/Main.java +++ b/test/566-polymorphic-inlining/src/Main.java @@ -98,6 +98,7 @@ public class Main implements Itf { public static native void ensureJittedAndPolymorphicInline(); public void increment() { + field.getClass(); // null check to ensure we get an inlined frame in the CodeInfo counter++; } public static int counter = 0; diff --git a/test/570-checker-osr/osr.cc b/test/570-checker-osr/osr.cc index bd8f0a9520..2fa5800e5c 100644 --- a/test/570-checker-osr/osr.cc +++ b/test/570-checker-osr/osr.cc @@ -14,7 +14,7 @@ * limitations under the License. */ -#include "art_method.h" +#include "art_method-inl.h" #include "jit/jit.h" #include "jit/jit_code_cache.h" #include "jit/profiling_info.h" diff --git a/test/595-profile-saving/profile-saving.cc b/test/595-profile-saving/profile-saving.cc index a7e6f8ba8c..0d26f454c6 100644 --- a/test/595-profile-saving/profile-saving.cc +++ b/test/595-profile-saving/profile-saving.cc @@ -16,6 +16,7 @@ #include "dex_file.h" +#include "art_method-inl.h" #include "jit/offline_profiling_info.h" #include "jit/profile_saver.h" #include "jni.h" diff --git a/test/595-profile-saving/run b/test/595-profile-saving/run index f12fac9207..068ad03ce0 100644 --- a/test/595-profile-saving/run +++ b/test/595-profile-saving/run @@ -16,13 +16,12 @@ # Use # --compiler-filter=interpret-only to make sure that the test is not compiled AOT -# -XOatFileManagerCompilerFilter:interpret-only to make sure the test is not compiled -# when loaded (by PathClassLoader) +# and to make sure the test is not compiled when loaded (by PathClassLoader) # -Xjitsaveprofilinginfo to enable profile saving # -Xusejit:false to disable jit and only test profiles. exec ${RUN} \ -Xcompiler-option --compiler-filter=interpret-only \ - --runtime-option -XOatFileManagerCompilerFilter:interpret-only \ + --runtime-option '-Xcompiler-option --compiler-filter=interpret-only' \ --runtime-option -Xjitsaveprofilinginfo \ --runtime-option -Xusejit:false \ "${@}" diff --git a/test/596-app-images/app_images.cc b/test/596-app-images/app_images.cc index 11c0f424ba..a5bbf5fbaa 100644 --- a/test/596-app-images/app_images.cc +++ b/test/596-app-images/app_images.cc @@ -14,7 +14,6 @@ * limitations under the License. */ -#include <assert.h> #include <iostream> #include <pthread.h> #include <stdio.h> diff --git a/test/597-deopt-new-string/deopt.cc b/test/597-deopt-new-string/deopt.cc new file mode 100644 index 0000000000..844a786e1e --- /dev/null +++ b/test/597-deopt-new-string/deopt.cc @@ -0,0 +1,59 @@ +/* + * 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 "jni.h" +#include "mirror/class-inl.h" +#include "runtime.h" +#include "thread_list.h" +#include "thread_state.h" +#include "gc/gc_cause.h" +#include "gc/scoped_gc_critical_section.h" + +namespace art { + +extern "C" JNIEXPORT void JNICALL Java_Main_deoptimizeAll( + JNIEnv* env, + jclass cls ATTRIBUTE_UNUSED) { + ScopedObjectAccess soa(env); + ScopedThreadSuspension sts(Thread::Current(), kWaitingForDeoptimization); + gc::ScopedGCCriticalSection gcs(Thread::Current(), + gc::kGcCauseInstrumentation, + gc::kCollectorTypeInstrumentation); + // We need to suspend mutator threads first. + ScopedSuspendAll ssa(__FUNCTION__); + static bool first = true; + if (first) { + // We need to enable deoptimization once in order to call DeoptimizeEverything(). + Runtime::Current()->GetInstrumentation()->EnableDeoptimization(); + first = false; + } + Runtime::Current()->GetInstrumentation()->DeoptimizeEverything("test"); +} + +extern "C" JNIEXPORT void JNICALL Java_Main_undeoptimizeAll( + JNIEnv* env, + jclass cls ATTRIBUTE_UNUSED) { + ScopedObjectAccess soa(env); + ScopedThreadSuspension sts(Thread::Current(), kWaitingForDeoptimization); + gc::ScopedGCCriticalSection gcs(Thread::Current(), + gc::kGcCauseInstrumentation, + gc::kCollectorTypeInstrumentation); + // We need to suspend mutator threads first. + ScopedSuspendAll ssa(__FUNCTION__); + Runtime::Current()->GetInstrumentation()->UndeoptimizeEverything("test"); +} + +} // namespace art diff --git a/test/597-deopt-new-string/expected.txt b/test/597-deopt-new-string/expected.txt new file mode 100644 index 0000000000..f993efcdad --- /dev/null +++ b/test/597-deopt-new-string/expected.txt @@ -0,0 +1,2 @@ +JNI_OnLoad called +Finishing diff --git a/test/597-deopt-new-string/info.txt b/test/597-deopt-new-string/info.txt new file mode 100644 index 0000000000..1bd1f79c04 --- /dev/null +++ b/test/597-deopt-new-string/info.txt @@ -0,0 +1 @@ +Regression test for b/28555675 diff --git a/test/597-deopt-new-string/run b/test/597-deopt-new-string/run new file mode 100644 index 0000000000..9776ab3eb4 --- /dev/null +++ b/test/597-deopt-new-string/run @@ -0,0 +1,18 @@ +#!/bin/bash +# +# 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. + +# We want to run in debuggable mode which keeps the call into StringFactory.newEmptyString(). +exec ${RUN} -Xcompiler-option --debuggable "${@}" diff --git a/test/597-deopt-new-string/src/Main.java b/test/597-deopt-new-string/src/Main.java new file mode 100644 index 0000000000..1224e407b0 --- /dev/null +++ b/test/597-deopt-new-string/src/Main.java @@ -0,0 +1,75 @@ +/* + * 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 Main implements Runnable { + static final int numberOfThreads = 2; + static final int totalOperations = 40000; + static boolean sFlag = false; + static volatile boolean done = false; + int threadIndex; + + public static native void deoptimizeAll(); + public static native void undeoptimizeAll(); + + Main(int index) { + threadIndex = index; + } + + public static void main(String[] args) throws Exception { + System.loadLibrary(args[0]); + + final Thread[] threads = new Thread[numberOfThreads]; + for (int t = 0; t < threads.length; t++) { + threads[t] = new Thread(new Main(t)); + threads[t].start(); + } + for (Thread t : threads) { + t.join(); + } + System.out.println("Finishing"); + } + + public String $noinline$run0() { + // Prevent inlining. + if (sFlag) { + throw new Error(); + } + char[] arr = {'a', 'b', 'c'}; + return new String(arr, 0, arr.length); + } + + public void run() { + if (threadIndex == 0) { + // This thread keeps doing deoptimization of all threads. + // Hopefully that will trigger one deoptimization when returning from + // StringFactory.newEmptyString() in one of the other threads. + for (int i = 0; i < totalOperations; ++i) { + if (i % 50 == 0) { + deoptimizeAll(); + } + if (i % 50 == 25) { + undeoptimizeAll(); + } + } + done = true; + } else { + // This thread keeps doing new String() from a char array. + while (!done) { + $noinline$run0(); + } + } + } +} diff --git a/test/Android.libarttest.mk b/test/Android.libarttest.mk index d6f5d372a9..21f8141c66 100644 --- a/test/Android.libarttest.mk +++ b/test/Android.libarttest.mk @@ -43,7 +43,8 @@ LIBARTTEST_COMMON_SRC_FILES := \ 566-polymorphic-inlining/polymorphic_inline.cc \ 570-checker-osr/osr.cc \ 595-profile-saving/profile-saving.cc \ - 596-app-images/app_images.cc + 596-app-images/app_images.cc \ + 597-deopt-new-string/deopt.cc ART_TARGET_LIBARTTEST_$(ART_PHONY_TEST_TARGET_SUFFIX) += $(ART_TARGET_TEST_OUT)/$(TARGET_ARCH)/libarttest.so ART_TARGET_LIBARTTEST_$(ART_PHONY_TEST_TARGET_SUFFIX) += $(ART_TARGET_TEST_OUT)/$(TARGET_ARCH)/libarttestd.so @@ -92,7 +93,12 @@ define build-libarttest include $(BUILD_SHARED_LIBRARY) else # host LOCAL_CLANG := $(ART_HOST_CLANG) - LOCAL_CFLAGS := $(ART_HOST_CFLAGS) $(ART_HOST_DEBUG_CFLAGS) + LOCAL_CFLAGS := $(ART_HOST_CFLAGS) + ifeq ($$(suffix),d) + LOCAL_CFLAGS += $(ART_HOST_DEBUG_CFLAGS) + else + LOCAL_CFLAGS += $(ART_HOST_NON_DEBUG_CFLAGS) + endif LOCAL_ASFLAGS := $(ART_HOST_ASFLAGS) LOCAL_LDLIBS := $(ART_HOST_LDLIBS) -ldl -lpthread LOCAL_IS_HOST_MODULE := true diff --git a/test/etc/run-test-jar b/test/etc/run-test-jar index d61fc8f8fc..01114b7690 100755 --- a/test/etc/run-test-jar +++ b/test/etc/run-test-jar @@ -323,11 +323,14 @@ fi if [ "$INTERPRETER" = "y" ]; then INT_OPTS="-Xint" if [ "$VERIFY" = "y" ] ; then + INT_OPTS="${INT_OPTS} -Xcompiler-option --compiler-filter=interpret-only" COMPILE_FLAGS="${COMPILE_FLAGS} --compiler-filter=interpret-only" elif [ "$VERIFY" = "s" ]; then + INT_OPTS="${INT_OPTS} -Xcompiler-option --compiler-filter=verify-at-runtime" COMPILE_FLAGS="${COMPILE_FLAGS} --compiler-filter=verify-at-runtime" DEX_VERIFY="${DEX_VERIFY} -Xverify:softfail" else # VERIFY = "n" + INT_OPTS="${INT_OPTS} -Xcompiler-option --compiler-filter=verify-none" COMPILE_FLAGS="${COMPILE_FLAGS} --compiler-filter=verify-none" DEX_VERIFY="${DEX_VERIFY} -Xverify:none" fi @@ -336,18 +339,12 @@ fi if [ "$JIT" = "y" ]; then INT_OPTS="-Xusejit:true" if [ "$VERIFY" = "y" ] ; then + INT_OPTS="${INT_OPTS} -Xcompiler-option --compiler-filter=verify-at-runtime" COMPILE_FLAGS="${COMPILE_FLAGS} --compiler-filter=verify-at-runtime" - if [ "$PREBUILD" = "n" ]; then - # Make sure that if we have noprebuild we still JIT as DexClassLoader will - # try to compile the dex file. - INT_OPTS="${INT_OPTS} -Xcompiler-option --compiler-filter=verify-at-runtime" - fi else + INT_OPTS="${INT_OPTS} -Xcompiler-option --compiler-filter=verify-none" COMPILE_FLAGS="${COMPILE_FLAGS} --compiler-filter=verify-none" DEX_VERIFY="${DEX_VERIFY} -Xverify:none" - if [ "$PREBUILD" = "n" ]; then - INT_OPTS="${INT_OPTS} -Xcompiler-option --compiler-filter=verify-none" - fi fi fi diff --git a/test/run-test b/test/run-test index fc57d0914f..424c54f2c9 100755 --- a/test/run-test +++ b/test/run-test @@ -244,11 +244,11 @@ while true; do run_args="${run_args} --zygote" shift elif [ "x$1" = "x--interpreter" ]; then - run_args="${run_args} --interpreter --runtime-option -XOatFileManagerCompilerFilter:verify-at-runtime" + run_args="${run_args} --interpreter" image_suffix="-interpreter" shift elif [ "x$1" = "x--jit" ]; then - run_args="${run_args} --jit --runtime-option -XOatFileManagerCompilerFilter:verify-at-runtime" + run_args="${run_args} --jit" image_suffix="-jit" shift elif [ "x$1" = "x--optimizing" ]; then @@ -256,10 +256,10 @@ while true; do image_suffix="-optimizing" shift elif [ "x$1" = "x--no-verify" ]; then - run_args="${run_args} --no-verify --runtime-option -XOatFileManagerCompilerFilter:verify-none" + run_args="${run_args} --no-verify" shift elif [ "x$1" = "x--verify-soft-fail" ]; then - run_args="${run_args} --verify-soft-fail --runtime-option -XOatFileManagerCompilerFilter:verify-at-runtime" + run_args="${run_args} --verify-soft-fail" image_suffix="-interp-ac" shift elif [ "x$1" = "x--no-optimize" ]; then |