diff options
33 files changed, 384 insertions, 38 deletions
diff --git a/Android.mk b/Android.mk index e89f6178e7..a518d2f56f 100644 --- a/Android.mk +++ b/Android.mk @@ -270,9 +270,9 @@ endif test-art-host-dexdump: $(addprefix $(HOST_OUT_EXECUTABLES)/, dexdump2 dexlist) ANDROID_HOST_OUT=$(realpath $(HOST_OUT)) art/test/dexdump/run-all-tests -# Valgrind. Currently only 32b gtests. TODO: change this from 32-bit only to both 32-bit and 64-bit. +# Valgrind. .PHONY: valgrind-test-art-host -valgrind-test-art-host: valgrind-test-art-host-gtest32 +valgrind-test-art-host: valgrind-test-art-host-gtest $(hide) $(call ART_TEST_PREREQ_FINISHED,$@) .PHONY: valgrind-test-art-host32 diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc index 9acaa1d000..3b643a3c4f 100644 --- a/compiler/optimizing/code_generator_x86.cc +++ b/compiler/optimizing/code_generator_x86.cc @@ -4796,6 +4796,7 @@ void InstructionCodeGeneratorX86::HandleFieldSet(HInstruction* instruction, int32_t v = CodeGenerator::GetInt32ValueOf(value.GetConstant()); __ movl(Address(base, offset), Immediate(v)); } else { + DCHECK(value.IsRegister()) << value; __ movl(Address(base, offset), value.AsRegister<Register>()); } break; diff --git a/compiler/optimizing/load_store_elimination.cc b/compiler/optimizing/load_store_elimination.cc index 8eaac0bbd3..561dcfbb1f 100644 --- a/compiler/optimizing/load_store_elimination.cc +++ b/compiler/optimizing/load_store_elimination.cc @@ -728,6 +728,23 @@ class LSEVisitor : public HGraphVisitor { // This acts like GVN but with better aliasing analysis. heap_values[idx] = instruction; } else { + if (Primitive::PrimitiveKind(heap_value->GetType()) + != Primitive::PrimitiveKind(instruction->GetType())) { + // The only situation where the same heap location has different type is when + // we do an array get from a null constant. In order to stay properly typed + // we do not merge the array gets. + if (kIsDebugBuild) { + DCHECK(heap_value->IsArrayGet()) << heap_value->DebugName(); + DCHECK(instruction->IsArrayGet()) << instruction->DebugName(); + HInstruction* array = instruction->AsArrayGet()->GetArray(); + DCHECK(array->IsNullCheck()) << array->DebugName(); + DCHECK(array->InputAt(0)->IsNullConstant()) << array->InputAt(0)->DebugName(); + array = heap_value->AsArrayGet()->GetArray(); + DCHECK(array->IsNullCheck()) << array->DebugName(); + DCHECK(array->InputAt(0)->IsNullConstant()) << array->InputAt(0)->DebugName(); + } + return; + } removed_loads_.push_back(instruction); substitute_instructions_for_loads_.push_back(heap_value); TryRemovingNullCheck(instruction); diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc index a5d0c2797e..298101115d 100644 --- a/dex2oat/dex2oat.cc +++ b/dex2oat/dex2oat.cc @@ -255,6 +255,7 @@ NO_RETURN static void Usage(const char* fmt, ...) { UsageError(""); UsageError(" --compiler-filter=" "(verify-none" + "|verify-at-runtime" "|interpret-only" "|space" "|balanced" @@ -287,8 +288,8 @@ NO_RETURN static void Usage(const char* fmt, ...) { UsageError(""); UsageError(" --num-dex-methods=<method-count>: threshold size for a small dex file for"); UsageError(" compiler filter tuning. If the input has fewer than this many methods"); - UsageError(" and the filter is not interpret-only or verify-none, overrides the"); - UsageError(" filter to use speed"); + UsageError(" and the filter is not interpret-only or verify-none or verify-at-runtime, "); + UsageError(" overrides the filter to use speed"); UsageError(" Example: --num-dex-method=%d", CompilerOptions::kDefaultNumDexMethodsThreshold); UsageError(" Default: %d", CompilerOptions::kDefaultNumDexMethodsThreshold); UsageError(""); @@ -1449,8 +1450,8 @@ class Dex2Oat FINAL { } /* - * If we're not in interpret-only or verify-none mode, go ahead and compile small applications. - * Don't bother to check if we're doing the image. + * If we're not in interpret-only or verify-none or verify-at-runtime mode, go ahead and + * compile small applications. Don't bother to check if we're doing the image. */ if (!IsBootImage() && compiler_options_->IsCompilationEnabled() && diff --git a/runtime/arch/arm/quick_entrypoints_arm.S b/runtime/arch/arm/quick_entrypoints_arm.S index 64135d8f77..82ec0b7c09 100644 --- a/runtime/arch/arm/quick_entrypoints_arm.S +++ b/runtime/arch/arm/quick_entrypoints_arm.S @@ -1125,9 +1125,8 @@ ENTRY art_quick_alloc_object_tlab // r0: type_idx/return value, r1: ArtMethod*, r9: Thread::Current // r2, r3, r12: free. #if defined(USE_READ_BARRIER) - eor r0, r0, r0 // Read barrier not supported here. - sub r0, r0, #1 // Return -1. - bx lr + mvn r0, #0 // Read barrier not supported here. + bx lr // Return -1. #endif ldr r2, [r1, #ART_METHOD_DEX_CACHE_TYPES_OFFSET_32] // Load dex cache resolved types array // Load the class (r2) diff --git a/runtime/arch/arm64/quick_entrypoints_arm64.S b/runtime/arch/arm64/quick_entrypoints_arm64.S index e4c255809b..65d5b463c7 100644 --- a/runtime/arch/arm64/quick_entrypoints_arm64.S +++ b/runtime/arch/arm64/quick_entrypoints_arm64.S @@ -1638,7 +1638,79 @@ ENTRY art_quick_alloc_object_rosalloc RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER END art_quick_alloc_object_rosalloc -GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT(_tlab, TLAB) +// A hand-written override for GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT(_tlab, TLAB). +ENTRY art_quick_alloc_object_tlab + // Fast path tlab allocation. + // x0: type_idx/return value, x1: ArtMethod*, xSELF(x19): Thread::Current + // x2-x7: free. +#if defined(USE_READ_BARRIER) + mvn x0, xzr // Read barrier not supported here. + ret // Return -1. +#endif + ldr x2, [x1, #ART_METHOD_DEX_CACHE_TYPES_OFFSET_64] // Load dex cache resolved types array + // Load the class (x2) + ldr w2, [x2, x0, lsl #COMPRESSED_REFERENCE_SIZE_SHIFT] + cbz x2, .Lart_quick_alloc_object_tlab_slow_path // Check null class + // Check class status. + ldr w3, [x2, #MIRROR_CLASS_STATUS_OFFSET] + cmp x3, #MIRROR_CLASS_STATUS_INITIALIZED + bne .Lart_quick_alloc_object_tlab_slow_path + // Add a fake dependence from the + // following access flag and size + // loads to the status load. + // This is to prevent those loads + // from being reordered above the + // status load and reading wrong + // values (an alternative is to use + // a load-acquire for the status). + eor x3, x3, x3 + add x2, x2, x3 + // Check access flags has + // kAccClassIsFinalizable. + ldr w3, [x2, #MIRROR_CLASS_ACCESS_FLAGS_OFFSET] + tbnz x3, #ACCESS_FLAGS_CLASS_IS_FINALIZABLE_BIT, .Lart_quick_alloc_object_tlab_slow_path + // Load thread_local_pos (x4) and + // thread_local_end (x5). + ldr x4, [xSELF, #THREAD_LOCAL_POS_OFFSET] + ldr x5, [xSELF, #THREAD_LOCAL_END_OFFSET] + sub x6, x5, x4 // Compute the remaining buf size. + ldr w7, [x2, #MIRROR_CLASS_OBJECT_SIZE_OFFSET] // Load the object size (x7). + cmp x7, x6 // Check if it fits. OK to do this + // before rounding up the object size + // assuming the buf size alignment. + bhi .Lart_quick_alloc_object_tlab_slow_path + // "Point of no slow path". Won't go to the slow path from here on. OK to clobber x0 and x1. + // Round up the object size by the + // object alignment. (addr + 7) & ~7. + add x7, x7, #OBJECT_ALIGNMENT_MASK + and x7, x7, #OBJECT_ALIGNMENT_MASK_TOGGLED + // Move old thread_local_pos to x0 + // for the return value. + mov x0, x4 + add x5, x0, x7 + str x5, [xSELF, #THREAD_LOCAL_POS_OFFSET] // Store new thread_local_pos. + ldr x5, [xSELF, #THREAD_LOCAL_OBJECTS_OFFSET] // Increment thread_local_objects. + add x5, x5, #1 + str x5, [xSELF, #THREAD_LOCAL_OBJECTS_OFFSET] + POISON_HEAP_REF w2 + str w2, [x0, #MIRROR_OBJECT_CLASS_OFFSET] // Store the class pointer. + // Fence. This is "ish" not "ishst" so + // that the code after this allocation + // site will see the right values in + // the fields of the class. + // Alternatively we could use "ishst" + // if we use load-acquire for the + // class status load.) + dmb ish + ret +.Lart_quick_alloc_object_tlab_slow_path: + SETUP_REFS_ONLY_CALLEE_SAVE_FRAME // Save callee saves in case of GC. + mov x2, xSELF // Pass Thread::Current. + bl artAllocObjectFromCodeTLAB // (uint32_t type_idx, Method* method, Thread*) + RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME + RETURN_IF_RESULT_IS_NON_ZERO_OR_DELIVER +END art_quick_alloc_object_tlab + GENERATE_ALLOC_ENTRYPOINTS_ALLOC_OBJECT(_region_tlab, RegionTLAB) /* diff --git a/runtime/asm_support.h b/runtime/asm_support.h index d5f0dffc38..1f24f45fd0 100644 --- a/runtime/asm_support.h +++ b/runtime/asm_support.h @@ -230,6 +230,9 @@ ADD_TEST_EQ(static_cast<uint32_t>(MIRROR_CLASS_STATUS_INITIALIZED), #define ACCESS_FLAGS_CLASS_IS_FINALIZABLE 0x80000000 ADD_TEST_EQ(static_cast<uint32_t>(ACCESS_FLAGS_CLASS_IS_FINALIZABLE), static_cast<uint32_t>(art::kAccClassIsFinalizable)) +#define ACCESS_FLAGS_CLASS_IS_FINALIZABLE_BIT 31 +ADD_TEST_EQ(static_cast<uint32_t>(ACCESS_FLAGS_CLASS_IS_FINALIZABLE), + static_cast<uint32_t>(1U << ACCESS_FLAGS_CLASS_IS_FINALIZABLE_BIT)) // Array offsets. #define MIRROR_ARRAY_LENGTH_OFFSET MIRROR_OBJECT_HEADER_SIZE diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc index 902ba03ea5..d8e309d57e 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -4270,10 +4270,18 @@ void ClassLinker::CreateProxyMethod(Handle<mirror::Class> klass, ArtMethod* prot DCHECK(out != nullptr); out->CopyFrom(prototype, image_pointer_size_); - // Set class to be the concrete proxy class and clear the abstract flag, modify exceptions to - // the intersection of throw exceptions as defined in Proxy + // Set class to be the concrete proxy class. out->SetDeclaringClass(klass.Get()); - out->SetAccessFlags((out->GetAccessFlags() & ~kAccAbstract) | kAccFinal); + // Clear the abstract, default and conflict flags to ensure that defaults aren't picked in + // preference to the invocation handler. + const uint32_t kRemoveFlags = kAccAbstract | kAccDefault | kAccDefaultConflict; + // Make the method final. + const uint32_t kAddFlags = kAccFinal; + out->SetAccessFlags((out->GetAccessFlags() & ~kRemoveFlags) | kAddFlags); + + // Clear the dex_code_item_offset_. It needs to be 0 since proxy methods have no CodeItems but the + // method they copy might (if it's a default method). + out->SetCodeItemOffset(0); // At runtime the method looks like a reference and argument saving method, clone the code // related parameters from this method. diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc index 24986253f7..7005aa5548 100644 --- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc +++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc @@ -653,13 +653,13 @@ extern "C" uint64_t artQuickToInterpreterBridge(ArtMethod* method, Thread* self, JValue tmp_value; ShadowFrame* deopt_frame = self->PopStackedShadowFrame( StackedShadowFrameType::kSingleFrameDeoptimizationShadowFrame, false); - const DexFile::CodeItem* code_item = method->GetCodeItem(); - DCHECK(code_item != nullptr) << PrettyMethod(method); ManagedStack fragment; DCHECK(!method->IsNative()) << PrettyMethod(method); uint32_t shorty_len = 0; - auto* non_proxy_method = method->GetInterfaceMethodIfProxy(sizeof(void*)); + ArtMethod* non_proxy_method = method->GetInterfaceMethodIfProxy(sizeof(void*)); + const DexFile::CodeItem* code_item = non_proxy_method->GetCodeItem(); + DCHECK(code_item != nullptr) << PrettyMethod(method); const char* shorty = non_proxy_method->GetShorty(&shorty_len); JValue result; diff --git a/runtime/gc/space/image_space_fs.h b/runtime/gc/space/image_space_fs.h index ec4bf92a2a..5237466c00 100644 --- a/runtime/gc/space/image_space_fs.h +++ b/runtime/gc/space/image_space_fs.h @@ -26,6 +26,7 @@ #include "base/unix_file/fd_file.h" #include "globals.h" #include "os.h" +#include "runtime.h" #include "utils.h" namespace art { @@ -200,6 +201,11 @@ static void PruneDalvikCache(InstructionSet isa) { impl::DeleteDirectoryContents(GetDalvikCacheOrDie(".", false), false); // Prune /data/dalvik-cache/<isa>. impl::DeleteDirectoryContents(GetDalvikCacheOrDie(GetInstructionSetString(isa), false), false); + + // Be defensive. There should be a runtime created here, but this may be called in a test. + if (Runtime::Current() != nullptr) { + Runtime::Current()->SetPrunedDalvikCache(true); + } } // We write out an empty file to the zygote's ISA specific cache dir at the start of diff --git a/runtime/instrumentation.cc b/runtime/instrumentation.cc index b107b72b55..a0c6bfbd83 100644 --- a/runtime/instrumentation.cc +++ b/runtime/instrumentation.cc @@ -83,7 +83,8 @@ Instrumentation::Instrumentation() deoptimized_methods_lock_("deoptimized methods lock"), deoptimization_enabled_(false), interpreter_handler_table_(kMainHandlerTable), - quick_alloc_entry_points_instrumentation_counter_(0) { + quick_alloc_entry_points_instrumentation_counter_(0), + alloc_entrypoints_instrumented_(false) { } void Instrumentation::InstallStubsForClass(mirror::Class* klass) { @@ -642,10 +643,12 @@ void Instrumentation::SetEntrypointsInstrumented(bool instrumented) { MutexLock mu(self, *Locks::runtime_shutdown_lock_); SetQuickAllocEntryPointsInstrumented(instrumented); ResetQuickAllocEntryPoints(); + alloc_entrypoints_instrumented_ = instrumented; } else { MutexLock mu(self, *Locks::runtime_shutdown_lock_); SetQuickAllocEntryPointsInstrumented(instrumented); ResetQuickAllocEntryPoints(); + alloc_entrypoints_instrumented_ = instrumented; } } diff --git a/runtime/instrumentation.h b/runtime/instrumentation.h index b3cdb410f3..d07f47bf29 100644 --- a/runtime/instrumentation.h +++ b/runtime/instrumentation.h @@ -422,7 +422,7 @@ class Instrumentation { // Does not hold lock, used to check if someone changed from not instrumented to instrumented // during a GC suspend point. bool AllocEntrypointsInstrumented() const SHARED_REQUIRES(Locks::mutator_lock_) { - return quick_alloc_entry_points_instrumentation_counter_ > 0; + return alloc_entrypoints_instrumented_; } private: @@ -579,6 +579,12 @@ class Instrumentation { // Greater than 0 if quick alloc entry points instrumented. size_t quick_alloc_entry_points_instrumentation_counter_; + + // alloc_entrypoints_instrumented_ is only updated with all the threads suspended, this is done + // to prevent races with the GC where the GC relies on thread suspension only see + // alloc_entrypoints_instrumented_ change during suspend points. + bool alloc_entrypoints_instrumented_; + friend class InstrumentationTest; // For GetCurrentInstrumentationLevel and ConfigureStubs. DISALLOW_COPY_AND_ASSIGN(Instrumentation); diff --git a/runtime/interpreter/mterp/arm64/op_rem_double_2addr.S b/runtime/interpreter/mterp/arm64/op_rem_double_2addr.S index db18aa7ee2..9868f4123a 100644 --- a/runtime/interpreter/mterp/arm64/op_rem_double_2addr.S +++ b/runtime/interpreter/mterp/arm64/op_rem_double_2addr.S @@ -3,9 +3,9 @@ ubfx w2, wINST, #8, #4 // w2<- A GET_VREG_WIDE d1, w1 // d1<- vB GET_VREG_WIDE d0, w2 // d0<- vA - FETCH_ADVANCE_INST 1 // advance rPC, load rINST bl fmod ubfx w2, wINST, #8, #4 // w2<- A (need to reload - killed across call) + FETCH_ADVANCE_INST 1 // advance rPC, load rINST GET_INST_OPCODE ip // extract opcode from rINST SET_VREG_WIDE d0, w2 // vAA<- result GOTO_OPCODE ip // jump to next instruction diff --git a/runtime/interpreter/mterp/out/mterp_arm64.S b/runtime/interpreter/mterp/out/mterp_arm64.S index cdb27e89e6..6ae59d857f 100644 --- a/runtime/interpreter/mterp/out/mterp_arm64.S +++ b/runtime/interpreter/mterp/out/mterp_arm64.S @@ -5984,9 +5984,9 @@ artMterpAsmInstructionStart = .L_op_nop ubfx w2, wINST, #8, #4 // w2<- A GET_VREG_WIDE d1, w1 // d1<- vB GET_VREG_WIDE d0, w2 // d0<- vA - FETCH_ADVANCE_INST 1 // advance rPC, load rINST bl fmod ubfx w2, wINST, #8, #4 // w2<- A (need to reload - killed across call) + FETCH_ADVANCE_INST 1 // advance rPC, load rINST GET_INST_OPCODE ip // extract opcode from rINST SET_VREG_WIDE d0, w2 // vAA<- result GOTO_OPCODE ip // jump to next instruction diff --git a/runtime/native/dalvik_system_VMRuntime.cc b/runtime/native/dalvik_system_VMRuntime.cc index f6b2f21515..4ac28ae593 100644 --- a/runtime/native/dalvik_system_VMRuntime.cc +++ b/runtime/native/dalvik_system_VMRuntime.cc @@ -622,6 +622,11 @@ static jstring VMRuntime_getCurrentInstructionSet(JNIEnv* env, jclass) { return env->NewStringUTF(GetInstructionSetString(kRuntimeISA)); } +static jboolean VMRuntime_didPruneDalvikCache(JNIEnv* env ATTRIBUTE_UNUSED, + jclass klass ATTRIBUTE_UNUSED) { + return Runtime::Current()->GetPrunedDalvikCache() ? JNI_TRUE : JNI_FALSE; +} + static JNINativeMethod gMethods[] = { NATIVE_METHOD(VMRuntime, addressOf, "!(Ljava/lang/Object;)J"), NATIVE_METHOD(VMRuntime, bootClassPath, "()Ljava/lang/String;"), @@ -657,6 +662,7 @@ static JNINativeMethod gMethods[] = { "(Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;)V"), NATIVE_METHOD(VMRuntime, isBootClassPathOnDisk, "(Ljava/lang/String;)Z"), NATIVE_METHOD(VMRuntime, getCurrentInstructionSet, "()Ljava/lang/String;"), + NATIVE_METHOD(VMRuntime, didPruneDalvikCache, "()Z"), }; void register_dalvik_system_VMRuntime(JNIEnv* env) { diff --git a/runtime/oat_file_manager.cc b/runtime/oat_file_manager.cc index e57125bef1..3ec3826374 100644 --- a/runtime/oat_file_manager.cc +++ b/runtime/oat_file_manager.cc @@ -477,4 +477,23 @@ void OatFileManager::UnRegisterOatFileLocation(const std::string& oat_location) } } +void OatFileManager::DumpForSigQuit(std::ostream& os) { + ReaderMutexLock mu(Thread::Current(), *Locks::oat_file_manager_lock_); + std::vector<const OatFile*> boot_oat_files = GetBootOatFiles(); + for (const std::unique_ptr<const OatFile>& oat_file : oat_files_) { + if (ContainsElement(boot_oat_files, oat_file.get())) { + continue; + } + // Use "platform-default" if it's neither extract nor profile guided. + // Saying 'full' could be misleading if for example the platform uses + // compiler filters. + const char* status = oat_file->IsExtractOnly() + ? OatHeader::kExtractOnlyValue + : oat_file->IsProfileGuideCompiled() + ? OatHeader::kProfileGuideCompiledValue + : "platform-default"; + os << oat_file->GetLocation() << ": " << status << "\n"; + } +} + } // namespace art diff --git a/runtime/oat_file_manager.h b/runtime/oat_file_manager.h index c508c4bf07..a541d1022b 100644 --- a/runtime/oat_file_manager.h +++ b/runtime/oat_file_manager.h @@ -108,6 +108,8 @@ class OatFileManager { /*out*/ std::vector<std::string>* error_msgs) REQUIRES(!Locks::oat_file_manager_lock_, !Locks::mutator_lock_); + void DumpForSigQuit(std::ostream& os); + 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. diff --git a/runtime/runtime.cc b/runtime/runtime.cc index 78e00fdbde..5284c9377e 100644 --- a/runtime/runtime.cc +++ b/runtime/runtime.cc @@ -208,7 +208,8 @@ Runtime::Runtime() experimental_flags_(ExperimentalFlags::kNone), oat_file_manager_(nullptr), is_low_memory_mode_(false), - safe_mode_(false) { + safe_mode_(false), + pruned_dalvik_cache_(false) { CheckAsmSupportOffsetsAndSizes(); std::fill(callee_save_methods_, callee_save_methods_ + arraysize(callee_save_methods_), 0u); interpreter::CheckInterpreterAsmConstants(); @@ -1363,6 +1364,7 @@ void Runtime::DumpForSigQuit(std::ostream& os) { GetInternTable()->DumpForSigQuit(os); GetJavaVM()->DumpForSigQuit(os); GetHeap()->DumpForSigQuit(os); + oat_file_manager_->DumpForSigQuit(os); if (GetJit() != nullptr) { GetJit()->DumpForSigQuit(os); } else { diff --git a/runtime/runtime.h b/runtime/runtime.h index aff7c067d3..36ad7f1087 100644 --- a/runtime/runtime.h +++ b/runtime/runtime.h @@ -618,6 +618,14 @@ class Runtime { return dump_native_stack_on_sig_quit_; } + bool GetPrunedDalvikCache() const { + return pruned_dalvik_cache_; + } + + void SetPrunedDalvikCache(bool pruned) { + pruned_dalvik_cache_ = pruned; + } + private: static void InitPlatformSignalHandlers(); @@ -833,6 +841,9 @@ class Runtime { // Whether threads should dump their native stack on SIGQUIT. bool dump_native_stack_on_sig_quit_; + // Whether the dalvik cache was pruned when initializing the runtime. + bool pruned_dalvik_cache_; + DISALLOW_COPY_AND_ASSIGN(Runtime); }; std::ostream& operator<<(std::ostream& os, const Runtime::CalleeSaveType& rhs); diff --git a/runtime/thread_list.cc b/runtime/thread_list.cc index afb11d33e9..a9ce056fd9 100644 --- a/runtime/thread_list.cc +++ b/runtime/thread_list.cc @@ -133,22 +133,24 @@ void ThreadList::DumpForSigQuit(std::ostream& os) { suspend_all_historam_.PrintConfidenceIntervals(os, 0.99, data); // Dump time to suspend. } } - Dump(os, Runtime::Current()->GetDumpNativeStackOnSigQuit()); - DumpUnattachedThreads(os); + bool dump_native_stack = Runtime::Current()->GetDumpNativeStackOnSigQuit(); + Dump(os, dump_native_stack); + DumpUnattachedThreads(os, dump_native_stack); } -static void DumpUnattachedThread(std::ostream& os, pid_t tid) NO_THREAD_SAFETY_ANALYSIS { +static void DumpUnattachedThread(std::ostream& os, pid_t tid, bool dump_native_stack) + NO_THREAD_SAFETY_ANALYSIS { // TODO: No thread safety analysis as DumpState with a null thread won't access fields, should // refactor DumpState to avoid skipping analysis. Thread::DumpState(os, nullptr, tid); DumpKernelStack(os, tid, " kernel: ", false); - if (kDumpUnattachedThreadNativeStack) { + if (dump_native_stack && kDumpUnattachedThreadNativeStack) { DumpNativeStack(os, tid, nullptr, " native: "); } os << "\n"; } -void ThreadList::DumpUnattachedThreads(std::ostream& os) { +void ThreadList::DumpUnattachedThreads(std::ostream& os, bool dump_native_stack) { DIR* d = opendir("/proc/self/task"); if (!d) { return; @@ -166,7 +168,7 @@ void ThreadList::DumpUnattachedThreads(std::ostream& os) { contains = Contains(tid); } if (!contains) { - DumpUnattachedThread(os, tid); + DumpUnattachedThread(os, tid, dump_native_stack); } } } diff --git a/runtime/thread_list.h b/runtime/thread_list.h index 363cab83f4..f97ecd34a5 100644 --- a/runtime/thread_list.h +++ b/runtime/thread_list.h @@ -161,7 +161,7 @@ class ThreadList { size_t RunCheckpoint(Closure* checkpoint_function, bool includeSuspended) REQUIRES(!Locks::thread_list_lock_, !Locks::thread_suspend_count_lock_); - void DumpUnattachedThreads(std::ostream& os) + void DumpUnattachedThreads(std::ostream& os, bool dump_native_stack) REQUIRES(!Locks::thread_list_lock_); void SuspendAllDaemonThreadsForShutdown() diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc index 4019656c93..537d9c9311 100644 --- a/runtime/verifier/method_verifier.cc +++ b/runtime/verifier/method_verifier.cc @@ -3992,13 +3992,17 @@ ArtMethod* MethodVerifier::VerifyInvocationArgs( // TODO Can we verify anything else. if (class_idx == class_def_->class_idx_) { Fail(VERIFY_ERROR_CLASS_CHANGE) << "Cannot invoke-super on self as interface"; + return nullptr; } // TODO Revisit whether we want to allow invoke-super on direct interfaces only like the JLS // does. - mirror::Class* this_class = GetDeclaringClass().GetClass(); - if (!reference_class->IsAssignableFrom(this_class)) { + if (!GetDeclaringClass().HasClass()) { + Fail(VERIFY_ERROR_NO_CLASS) << "Unable to resolve the full class of 'this' used in an" + << "interface invoke-super"; + return nullptr; + } else if (!reference_class->IsAssignableFrom(GetDeclaringClass().GetClass())) { Fail(VERIFY_ERROR_CLASS_CHANGE) - << "invoke-super in " << PrettyClass(this_class) << " in method " + << "invoke-super in " << PrettyClass(GetDeclaringClass().GetClass()) << " in method " << PrettyMethod(dex_method_idx_, *dex_file_) << " to method " << PrettyMethod(method_idx, *dex_file_) << " references " << "non-super-interface type " << PrettyClass(reference_class); diff --git a/test/003-omnibus-opcodes/src/FloatMath.java b/test/003-omnibus-opcodes/src/FloatMath.java index 96befe9cdc..fcdb4fe305 100644 --- a/test/003-omnibus-opcodes/src/FloatMath.java +++ b/test/003-omnibus-opcodes/src/FloatMath.java @@ -135,7 +135,8 @@ public class FloatMath { static float[] floatOperTest(float x, float y) { System.out.println("FloatMath.floatOperTest"); - float[] results = new float[9]; + float[] results = new float[10]; + float tmp; /* this seems to generate "op-float" instructions */ results[0] = x + y; @@ -145,7 +146,21 @@ public class FloatMath { results[4] = x % -y; /* this seems to generate "op-float/2addr" instructions */ - results[8] = x + (((((x + y) - y) * y) / y) % y); + tmp = x; + tmp += y; + results[5] = tmp; + tmp = x; + tmp -= y; + results[6] = tmp; + tmp = x; + tmp *= y; + results[7] = tmp; + tmp = x; + tmp /= y; + results[8] = tmp; + tmp = x; + tmp %= -y; + results[9] = tmp; return results; } @@ -155,7 +170,11 @@ public class FloatMath { Main.assertTrue(results[2] > -210000.01f && results[2] < -209999.99f); Main.assertTrue(results[3] > -23333.34f && results[3] < -23333.32f); Main.assertTrue(results[4] > 0.999f && results[4] < 1.001f); - Main.assertTrue(results[8] > 70000.99f && results[8] < 70001.01f); + Main.assertTrue(results[5] > 69996.99f && results[5] < 69997.01f); + Main.assertTrue(results[6] > 70002.99f && results[6] < 70003.01f); + Main.assertTrue(results[7] > -210000.01f && results[7] < -209999.99f); + Main.assertTrue(results[8] > -23333.34f && results[8] < -23333.32f); + Main.assertTrue(results[9] > 0.999f && results[9] < 1.001f); } /* @@ -165,7 +184,8 @@ public class FloatMath { static double[] doubleOperTest(double x, double y) { System.out.println("FloatMath.doubleOperTest"); - double[] results = new double[9]; + double[] results = new double[10]; + double tmp; /* this seems to generate "op-double" instructions */ results[0] = x + y; @@ -175,7 +195,21 @@ public class FloatMath { results[4] = x % -y; /* this seems to generate "op-double/2addr" instructions */ - results[8] = x + (((((x + y) - y) * y) / y) % y); + tmp = x; + tmp += y; + results[5] = tmp; + tmp = x; + tmp -= y; + results[6] = tmp; + tmp = x; + tmp *= y; + results[7] = tmp; + tmp = x; + tmp /= y; + results[8] = tmp; + tmp = x; + tmp %= -y; + results[9] = tmp; return results; } @@ -185,7 +219,11 @@ public class FloatMath { Main.assertTrue(results[2] > -210000.01 && results[2] < -209999.99); Main.assertTrue(results[3] > -23333.34 && results[3] < -23333.32); Main.assertTrue(results[4] > 0.999 && results[4] < 1.001); - Main.assertTrue(results[8] > 70000.99 && results[8] < 70001.01); + Main.assertTrue(results[5] > 69996.99 && results[5] < 69997.01); + Main.assertTrue(results[6] > 70002.99 && results[6] < 70003.01); + Main.assertTrue(results[7] > -210000.01 && results[7] < -209999.99); + Main.assertTrue(results[8] > -23333.34 && results[8] < -23333.32); + Main.assertTrue(results[9] > 0.999 && results[9] < 1.001); } /* diff --git a/test/586-checker-null-array-get/expected.txt b/test/586-checker-null-array-get/expected.txt new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/test/586-checker-null-array-get/expected.txt diff --git a/test/586-checker-null-array-get/info.txt b/test/586-checker-null-array-get/info.txt new file mode 100644 index 0000000000..81b42e9789 --- /dev/null +++ b/test/586-checker-null-array-get/info.txt @@ -0,0 +1,3 @@ +Regression test for the load store elimination of optimizing +that used to merge two array gets that have the same inputs but +not the same type. Note that this only happens if the array is null. diff --git a/test/586-checker-null-array-get/src/Main.java b/test/586-checker-null-array-get/src/Main.java new file mode 100644 index 0000000000..4b03ff28eb --- /dev/null +++ b/test/586-checker-null-array-get/src/Main.java @@ -0,0 +1,42 @@ +/* + * 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 { + public static Object[] getObjectArray() { return null; } + public static long[] getLongArray() { return null; } + + public static void main(String[] args) { + try { + foo(); + throw new Error("Expected NullPointerException"); + } catch (NullPointerException e) { + // Expected. + } + } + + /// CHECK-START: void Main.foo() load_store_elimination (after) + /// CHECK-DAG: <<Null:l\d+>> NullConstant + /// CHECK-DAG: <<Check:l\d+>> NullCheck [<<Null>>] + /// CHECK-DAG: <<Get1:j\d+>> ArrayGet [<<Check>>,{{i\d+}}] + /// CHECK-DAG: <<Get2:l\d+>> ArrayGet [<<Check>>,{{i\d+}}] + public static void foo() { + longField = getLongArray()[0]; + objectField = getObjectArray()[0]; + } + + public static long longField; + public static Object objectField; +} diff --git a/test/974-verify-interface-super/expected.txt b/test/974-verify-interface-super/expected.txt new file mode 100644 index 0000000000..7ba7491891 --- /dev/null +++ b/test/974-verify-interface-super/expected.txt @@ -0,0 +1 @@ +OK. No exception before invoke! diff --git a/test/974-verify-interface-super/info.txt b/test/974-verify-interface-super/info.txt new file mode 100644 index 0000000000..c5ff1f69f1 --- /dev/null +++ b/test/974-verify-interface-super/info.txt @@ -0,0 +1,3 @@ +Test that we do the right thing with invoke-super on interfaces when there are +verifier errors. + diff --git a/test/974-verify-interface-super/smali/base.smali b/test/974-verify-interface-super/smali/base.smali new file mode 100644 index 0000000000..c7875de1d3 --- /dev/null +++ b/test/974-verify-interface-super/smali/base.smali @@ -0,0 +1,31 @@ +# Copyright 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. + +.class public LBase; + +.super La/klass/that/does/not/Exist; + +.method public static run()V + .locals 4 + new-instance v0, LBase; + invoke-direct {v0}, LBase;-><init>()V + invoke-virtual {v0}, LBase;->SayHi()V + return-void +.end method + +.method public SayHi()V +.locals 2 + invoke-super {p0}, LIface;->SayHi()V + return-void +.end method diff --git a/test/974-verify-interface-super/smali/iface.smali b/test/974-verify-interface-super/smali/iface.smali new file mode 100644 index 0000000000..89f9c0beba --- /dev/null +++ b/test/974-verify-interface-super/smali/iface.smali @@ -0,0 +1,22 @@ +# Copyright 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. + +.class public abstract interface LIface; + +.super Ljava/lang/Object; + +.method public SayHi()V +.locals 0 + return-void +.end method diff --git a/test/974-verify-interface-super/smali/main.smali b/test/974-verify-interface-super/smali/main.smali new file mode 100644 index 0000000000..be4016c5c1 --- /dev/null +++ b/test/974-verify-interface-super/smali/main.smali @@ -0,0 +1,40 @@ +# Copyright 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. + +.class public LMain; + +.super Ljava/lang/Object; + +.method public static main([Ljava/lang/String;)V + .locals 4 + const-string v0, "OK. No exception before invoke!" + sget-object v1, Ljava/lang/System;->out:Ljava/io/PrintStream; + invoke-virtual {v1, v0}, Ljava/io/PrintStream;->println(Ljava/lang/Object;)V + :try_start + invoke-static {}, LBase;->run()V + const-string v0, "FAIL: no exception!" + sget-object v1, Ljava/lang/System;->out:Ljava/io/PrintStream; + invoke-virtual {v1, v0}, Ljava/io/PrintStream;->println(Ljava/lang/Object;)V + goto :end + :try_end + .catch Ljava/lang/LinkageError; {:try_start .. :try_end} :end + .catch Ljava/lang/Throwable; {:try_start .. :try_end} :error + :error + move-exception v0 + sget-object v1, Ljava/lang/System;->out:Ljava/io/PrintStream; + invoke-virtual {v1, v0}, Ljava/io/PrintStream;->println(Ljava/lang/Object;)V + invoke-virtual {v0}, Ljava/lang/Throwable;->printStackTrace()V + :end + return-void +.end method diff --git a/test/etc/run-test-jar b/test/etc/run-test-jar index 2db1e6c947..b360f67874 100755 --- a/test/etc/run-test-jar +++ b/test/etc/run-test-jar @@ -66,6 +66,10 @@ while true; do fi LIB="$1" shift + elif [ "x$1" = "x--gc-stress" ]; then + # Give an extra 5 mins if we are gc-stress. + TIME_OUT_VALUE=$((${TIME_OUT_VALUE} + 300)) + shift elif [ "x$1" = "x--testlib" ]; then shift if [ "x$1" = "x" ]; then diff --git a/test/run-test b/test/run-test index 6bb154942c..3350b35783 100755 --- a/test/run-test +++ b/test/run-test @@ -389,7 +389,7 @@ if [ "$gc_verify" = "true" ]; then run_args="${run_args} --runtime-option -Xgc:preverify_rosalloc --runtime-option -Xgc:postverify_rosalloc" fi if [ "$gc_stress" = "true" ]; then - run_args="${run_args} --runtime-option -Xgc:SS,gcstress --runtime-option -Xms2m --runtime-option -Xmx16m" + run_args="${run_args} --gc-stress --runtime-option -Xgc:SS,gcstress --runtime-option -Xms2m --runtime-option -Xmx16m" fi if [ "$trace" = "true" ]; then run_args="${run_args} --runtime-option -Xmethod-trace --runtime-option -Xmethod-trace-file-size:2000000" |