diff options
| -rw-r--r-- | compiler/optimizing/code_generator_x86.cc | 2 | ||||
| -rw-r--r-- | compiler/optimizing/code_generator_x86_64.cc | 2 | ||||
| -rw-r--r-- | disassembler/disassembler_x86.cc | 2 | ||||
| -rw-r--r-- | runtime/dex_file_annotations.cc | 92 | ||||
| -rw-r--r-- | runtime/gc/heap.cc | 8 | ||||
| -rw-r--r-- | runtime/gc/heap.h | 7 | ||||
| -rw-r--r-- | runtime/interpreter/unstarted_runtime.cc | 14 | ||||
| -rw-r--r-- | runtime/interpreter/unstarted_runtime_list.h | 1 | ||||
| -rw-r--r-- | runtime/interpreter/unstarted_runtime_test.cc | 45 | ||||
| -rw-r--r-- | runtime/method_handles.cc | 44 | ||||
| -rw-r--r-- | runtime/mirror/emulated_stack_frame.h | 4 | ||||
| -rw-r--r-- | runtime/openjdkjvmti/ti_method.cc | 22 | ||||
| -rw-r--r-- | test/021-string2/src/Main.java | 7 | ||||
| -rw-r--r-- | test/910-methods/expected.txt | 2 | ||||
| -rw-r--r-- | test/956-methodhandles/src/Main.java | 34 | ||||
| -rwxr-xr-x | test/run-test | 2 | ||||
| -rwxr-xr-x | test/testrunner/testrunner.py | 135 | ||||
| -rw-r--r-- | tools/libcore_failures.txt | 12 |
18 files changed, 290 insertions, 145 deletions
diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc index 09612c8dbf..b779aed763 100644 --- a/compiler/optimizing/code_generator_x86.cc +++ b/compiler/optimizing/code_generator_x86.cc @@ -5262,7 +5262,7 @@ void InstructionCodeGeneratorX86::VisitArrayGet(HArrayGet* instruction) { // Branch cases into compressed and uncompressed for each index's type. uint32_t count_offset = mirror::String::CountOffset().Uint32Value(); NearLabel done, not_compressed; - __ testl(Address(obj, count_offset), Immediate(1)); + __ testb(Address(obj, count_offset), Immediate(1)); codegen_->MaybeRecordImplicitNullCheck(instruction); static_assert(static_cast<uint32_t>(mirror::StringCompressionFlag::kCompressed) == 0u, "Expecting 0=compressed, 1=uncompressed"); diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc index 0879992e32..179bf6d3d1 100644 --- a/compiler/optimizing/code_generator_x86_64.cc +++ b/compiler/optimizing/code_generator_x86_64.cc @@ -4720,7 +4720,7 @@ void InstructionCodeGeneratorX86_64::VisitArrayGet(HArrayGet* instruction) { // Branch cases into compressed and uncompressed for each index's type. uint32_t count_offset = mirror::String::CountOffset().Uint32Value(); NearLabel done, not_compressed; - __ testl(Address(obj, count_offset), Immediate(1)); + __ testb(Address(obj, count_offset), Immediate(1)); codegen_->MaybeRecordImplicitNullCheck(instruction); static_assert(static_cast<uint32_t>(mirror::StringCompressionFlag::kCompressed) == 0u, "Expecting 0=compressed, 1=uncompressed"); diff --git a/disassembler/disassembler_x86.cc b/disassembler/disassembler_x86.cc index ff05733345..a289433af5 100644 --- a/disassembler/disassembler_x86.cc +++ b/disassembler/disassembler_x86.cc @@ -1306,7 +1306,7 @@ DISASSEMBLER_ENTRY(cmp, has_modrm = true; reg_is_opcode = true; store = true; - immediate_bytes = ((instr[1] & 0x38) == 0) ? 1 : 0; + immediate_bytes = ((instr[1] & 0x38) == 0) ? (instr[0] == 0xF7 ? 4 : 1) : 0; break; case 0xFF: { diff --git a/runtime/dex_file_annotations.cc b/runtime/dex_file_annotations.cc index a95f94cabb..d39ea35a90 100644 --- a/runtime/dex_file_annotations.cc +++ b/runtime/dex_file_annotations.cc @@ -299,6 +299,7 @@ mirror::Object* ProcessEncodedAnnotation(Handle<mirror::Class> klass, const uint return result.GetL(); } +template <bool kTransactionActive> bool ProcessAnnotationValue(Handle<mirror::Class> klass, const uint8_t** annotation_ptr, DexFile::AnnotationValue* annotation_value, @@ -409,22 +410,21 @@ bool ProcessAnnotationValue(Handle<mirror::Class> klass, } PointerSize pointer_size = class_linker->GetImagePointerSize(); set_object = true; - DCHECK(!Runtime::Current()->IsActiveTransaction()); if (method->IsConstructor()) { if (pointer_size == PointerSize::k64) { element_object = mirror::Constructor::CreateFromArtMethod<PointerSize::k64, - false>(self, method); + kTransactionActive>(self, method); } else { element_object = mirror::Constructor::CreateFromArtMethod<PointerSize::k32, - false>(self, method); + kTransactionActive>(self, method); } } else { if (pointer_size == PointerSize::k64) { element_object = mirror::Method::CreateFromArtMethod<PointerSize::k64, - false>(self, method); + kTransactionActive>(self, method); } else { element_object = mirror::Method::CreateFromArtMethod<PointerSize::k32, - false>(self, method); + kTransactionActive>(self, method); } } if (element_object == nullptr) { @@ -449,9 +449,11 @@ bool ProcessAnnotationValue(Handle<mirror::Class> klass, set_object = true; PointerSize pointer_size = Runtime::Current()->GetClassLinker()->GetImagePointerSize(); if (pointer_size == PointerSize::k64) { - element_object = mirror::Field::CreateFromArtField<PointerSize::k64>(self, field, true); + element_object = mirror::Field::CreateFromArtField<PointerSize::k64, + kTransactionActive>(self, field, true); } else { - element_object = mirror::Field::CreateFromArtField<PointerSize::k32>(self, field, true); + element_object = mirror::Field::CreateFromArtField<PointerSize::k32, + kTransactionActive>(self, field, true); } if (element_object == nullptr) { return false; @@ -497,45 +499,49 @@ bool ProcessAnnotationValue(Handle<mirror::Class> klass, } DexFile::AnnotationValue new_annotation_value; for (uint32_t i = 0; i < size; ++i) { - if (!ProcessAnnotationValue(klass, &annotation, &new_annotation_value, - component_type, DexFile::kPrimitivesOrObjects)) { + if (!ProcessAnnotationValue<kTransactionActive>(klass, + &annotation, + &new_annotation_value, + component_type, + DexFile::kPrimitivesOrObjects)) { return false; } if (!component_type->IsPrimitive()) { mirror::Object* obj = new_annotation_value.value_.GetL(); - new_array->AsObjectArray<mirror::Object>()->SetWithoutChecks<false>(i, obj); + new_array->AsObjectArray<mirror::Object>()-> + SetWithoutChecks<kTransactionActive>(i, obj); } else { switch (new_annotation_value.type_) { case DexFile::kDexAnnotationByte: - new_array->AsByteArray()->SetWithoutChecks<false>( + new_array->AsByteArray()->SetWithoutChecks<kTransactionActive>( i, new_annotation_value.value_.GetB()); break; case DexFile::kDexAnnotationShort: - new_array->AsShortArray()->SetWithoutChecks<false>( + new_array->AsShortArray()->SetWithoutChecks<kTransactionActive>( i, new_annotation_value.value_.GetS()); break; case DexFile::kDexAnnotationChar: - new_array->AsCharArray()->SetWithoutChecks<false>( + new_array->AsCharArray()->SetWithoutChecks<kTransactionActive>( i, new_annotation_value.value_.GetC()); break; case DexFile::kDexAnnotationInt: - new_array->AsIntArray()->SetWithoutChecks<false>( + new_array->AsIntArray()->SetWithoutChecks<kTransactionActive>( i, new_annotation_value.value_.GetI()); break; case DexFile::kDexAnnotationLong: - new_array->AsLongArray()->SetWithoutChecks<false>( + new_array->AsLongArray()->SetWithoutChecks<kTransactionActive>( i, new_annotation_value.value_.GetJ()); break; case DexFile::kDexAnnotationFloat: - new_array->AsFloatArray()->SetWithoutChecks<false>( + new_array->AsFloatArray()->SetWithoutChecks<kTransactionActive>( i, new_annotation_value.value_.GetF()); break; case DexFile::kDexAnnotationDouble: - new_array->AsDoubleArray()->SetWithoutChecks<false>( + new_array->AsDoubleArray()->SetWithoutChecks<kTransactionActive>( i, new_annotation_value.value_.GetD()); break; case DexFile::kDexAnnotationBoolean: - new_array->AsBooleanArray()->SetWithoutChecks<false>( + new_array->AsBooleanArray()->SetWithoutChecks<kTransactionActive>( i, new_annotation_value.value_.GetZ()); break; default: @@ -611,8 +617,11 @@ mirror::Object* CreateAnnotationMember(Handle<mirror::Class> klass, annotation_method->GetReturnType(true /* resolve */))); DexFile::AnnotationValue annotation_value; - if (!ProcessAnnotationValue(klass, annotation, &annotation_value, method_return, - DexFile::kAllObjects)) { + if (!ProcessAnnotationValue<false>(klass, + annotation, + &annotation_value, + method_return, + DexFile::kAllObjects)) { return nullptr; } Handle<mirror::Object> value_object(hs.NewHandle(annotation_value.value_.GetL())); @@ -716,8 +725,18 @@ mirror::Object* GetAnnotationValue(Handle<mirror::Class> klass, return nullptr; } DexFile::AnnotationValue annotation_value; - if (!ProcessAnnotationValue(klass, &annotation, &annotation_value, array_class, - DexFile::kAllObjects)) { + bool result = Runtime::Current()->IsActiveTransaction() + ? ProcessAnnotationValue<true>(klass, + &annotation, + &annotation_value, + array_class, + DexFile::kAllObjects) + : ProcessAnnotationValue<false>(klass, + &annotation, + &annotation_value, + array_class, + DexFile::kAllObjects); + if (!result) { return nullptr; } if (annotation_value.type_ != expected_type) { @@ -949,8 +968,11 @@ mirror::Object* GetAnnotationDefaultValue(ArtMethod* method) { StackHandleScope<2> hs(Thread::Current()); Handle<mirror::Class> h_klass(hs.NewHandle(klass)); Handle<mirror::Class> return_type(hs.NewHandle(method->GetReturnType(true /* resolve */))); - if (!ProcessAnnotationValue(h_klass, &annotation, &annotation_value, return_type, - DexFile::kAllObjects)) { + if (!ProcessAnnotationValue<false>(h_klass, + &annotation, + &annotation_value, + return_type, + DexFile::kAllObjects)) { return nullptr; } return annotation_value.value_.GetL(); @@ -1201,8 +1223,11 @@ mirror::Class* GetEnclosingClass(Handle<mirror::Class> klass) { return nullptr; } DexFile::AnnotationValue annotation_value; - if (!ProcessAnnotationValue(klass, &annotation, &annotation_value, - ScopedNullHandle<mirror::Class>(), DexFile::kAllRaw)) { + if (!ProcessAnnotationValue<false>(klass, + &annotation, + &annotation_value, + ScopedNullHandle<mirror::Class>(), + DexFile::kAllRaw)) { return nullptr; } if (annotation_value.type_ != DexFile::kDexAnnotationMethod) { @@ -1252,9 +1277,11 @@ bool GetInnerClass(Handle<mirror::Class> klass, mirror::String** name) { return false; } DexFile::AnnotationValue annotation_value; - if (!ProcessAnnotationValue(klass, &annotation, &annotation_value, - ScopedNullHandle<mirror::Class>(), - DexFile::kAllObjects)) { + if (!ProcessAnnotationValue<false>(klass, + &annotation, + &annotation_value, + ScopedNullHandle<mirror::Class>(), + DexFile::kAllObjects)) { return false; } if (annotation_value.type_ != DexFile::kDexAnnotationNull && @@ -1283,8 +1310,11 @@ bool GetInnerClassFlags(Handle<mirror::Class> klass, uint32_t* flags) { return false; } DexFile::AnnotationValue annotation_value; - if (!ProcessAnnotationValue(klass, &annotation, &annotation_value, - ScopedNullHandle<mirror::Class>(), DexFile::kAllRaw)) { + if (!ProcessAnnotationValue<false>(klass, + &annotation, + &annotation_value, + ScopedNullHandle<mirror::Class>(), + DexFile::kAllRaw)) { return false; } if (annotation_value.type_ != DexFile::kDexAnnotationInt) { diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc index a78de37796..c933d04908 100644 --- a/runtime/gc/heap.cc +++ b/runtime/gc/heap.cc @@ -29,6 +29,7 @@ #include "base/arena_allocator.h" #include "base/dumpable.h" #include "base/histogram-inl.h" +#include "base/memory_tool.h" #include "base/stl_util.h" #include "base/systrace.h" #include "base/time_utils.h" @@ -188,6 +189,7 @@ Heap::Heap(size_t initial_size, disable_thread_flip_count_(0), thread_flip_running_(false), collector_type_running_(kCollectorTypeNone), + thread_running_gc_(nullptr), last_gc_type_(collector::kGcTypeNone), next_gc_type_(collector::kGcTypePartial), capacity_(capacity), @@ -286,7 +288,7 @@ Heap::Heap(size_t initial_size, if (foreground_collector_type_ == kCollectorTypeCC) { // Need to use a low address so that we can allocate a contiguous // 2 * Xmx space when there's no image (dex2oat for target). -#if defined(__LP64__) +#if defined(__LP64__) || !defined(ADDRESS_SANITIZER) CHECK_GE(300 * MB, non_moving_space_capacity); requested_alloc_space_begin = reinterpret_cast<uint8_t*>(300 * MB) - non_moving_space_capacity; #else @@ -367,7 +369,7 @@ Heap::Heap(size_t initial_size, &error_str)); CHECK(non_moving_space_mem_map != nullptr) << error_str; // Try to reserve virtual memory at a lower address if we have a separate non moving space. -#if defined(__LP64__) +#if defined(__LP64__) || !defined(ADDRESS_SANITIZER) request_begin = reinterpret_cast<uint8_t*>(300 * MB); #else // For 32-bit, use 0x20000000 because asan reserves 0x04000000 - 0x20000000. @@ -1386,6 +1388,7 @@ void Heap::StartGC(Thread* self, GcCause cause, CollectorType collector_type) { // Ensure there is only one GC at a time. WaitForGcToCompleteLocked(cause, self); collector_type_running_ = collector_type; + thread_running_gc_ = self; } void Heap::TrimSpaces(Thread* self) { @@ -2785,6 +2788,7 @@ void Heap::FinishGC(Thread* self, collector::GcType gc_type) { } // Reset. running_collection_is_blocking_ = false; + thread_running_gc_ = nullptr; // Wake anyone who may have been waiting for the GC to complete. gc_complete_cond_->Broadcast(self); } diff --git a/runtime/gc/heap.h b/runtime/gc/heap.h index a4d300b110..0d56213d0f 100644 --- a/runtime/gc/heap.h +++ b/runtime/gc/heap.h @@ -736,7 +736,9 @@ class Heap { bool IsMovingGCDisabled(Thread* self) REQUIRES(!*gc_complete_lock_) { MutexLock mu(self, *gc_complete_lock_); - return disable_moving_gc_count_ > 0; + // If we are in a GC critical section or the disable moving GC count is non zero then moving + // GC is guaranteed to not start. + return disable_moving_gc_count_ > 0 || thread_running_gc_ == self; } // Request an asynchronous trim. @@ -1189,6 +1191,9 @@ class Heap { // True while the garbage collector is running. volatile CollectorType collector_type_running_ GUARDED_BY(gc_complete_lock_); + // The thread currently running the GC. + volatile Thread* thread_running_gc_ GUARDED_BY(gc_complete_lock_); + // Last Gc type we ran. Used by WaitForConcurrentGc to know which Gc was waited on. volatile collector::GcType last_gc_type_ GUARDED_BY(gc_complete_lock_); collector::GcType next_gc_type_; diff --git a/runtime/interpreter/unstarted_runtime.cc b/runtime/interpreter/unstarted_runtime.cc index fc219450df..4a321e6d27 100644 --- a/runtime/interpreter/unstarted_runtime.cc +++ b/runtime/interpreter/unstarted_runtime.cc @@ -445,6 +445,20 @@ void UnstartedRuntime::UnstartedClassGetInnerClassFlags( result->SetI(mirror::Class::GetInnerClassFlags(klass, default_value)); } +void UnstartedRuntime::UnstartedClassGetSignatureAnnotation( + Thread* self, ShadowFrame* shadow_frame, JValue* result, size_t arg_offset) { + StackHandleScope<1> hs(self); + Handle<mirror::Class> klass(hs.NewHandle( + reinterpret_cast<mirror::Class*>(shadow_frame->GetVRegReference(arg_offset)))); + + if (klass->IsProxyClass() || klass->GetDexCache() == nullptr) { + result->SetL(nullptr); + return; + } + + result->SetL(annotations::GetSignatureAnnotationForClass(klass)); +} + void UnstartedRuntime::UnstartedClassIsAnonymousClass( Thread* self, ShadowFrame* shadow_frame, JValue* result, size_t arg_offset) { StackHandleScope<1> hs(self); diff --git a/runtime/interpreter/unstarted_runtime_list.h b/runtime/interpreter/unstarted_runtime_list.h index 929b747840..c6114da037 100644 --- a/runtime/interpreter/unstarted_runtime_list.h +++ b/runtime/interpreter/unstarted_runtime_list.h @@ -31,6 +31,7 @@ V(ClassGetDeclaringClass, "java.lang.Class java.lang.Class.getDeclaringClass()") \ V(ClassGetEnclosingClass, "java.lang.Class java.lang.Class.getEnclosingClass()") \ V(ClassGetInnerClassFlags, "int java.lang.Class.getInnerClassFlags(int)") \ + V(ClassGetSignatureAnnotation, "java.lang.String[] java.lang.Class.getSignatureAnnotation()") \ V(ClassIsAnonymousClass, "boolean java.lang.Class.isAnonymousClass()") \ V(ClassLoaderGetResourceAsStream, "java.io.InputStream java.lang.ClassLoader.getResourceAsStream(java.lang.String)") \ V(VmClassLoaderFindLoadedClass, "java.lang.Class java.lang.VMClassLoader.findLoadedClass(java.lang.ClassLoader, java.lang.String)") \ diff --git a/runtime/interpreter/unstarted_runtime_test.cc b/runtime/interpreter/unstarted_runtime_test.cc index 3a0d0e71c2..4186c37dbc 100644 --- a/runtime/interpreter/unstarted_runtime_test.cc +++ b/runtime/interpreter/unstarted_runtime_test.cc @@ -29,6 +29,8 @@ #include "handle_scope-inl.h" #include "interpreter/interpreter_common.h" #include "mirror/class_loader.h" +#include "mirror/object_array-inl.h" +#include "mirror/object-inl.h" #include "mirror/string-inl.h" #include "runtime.h" #include "scoped_thread_state_change-inl.h" @@ -1077,9 +1079,9 @@ TEST_F(UnstartedRuntimeTest, LogManager) { StackHandleScope<1> hs(self); ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); Handle<mirror::Class> log_manager_class = hs.NewHandle( - class_linker->FindClass(self, - "Ljava/util/logging/LogManager;", - ScopedNullHandle<mirror::ClassLoader>())); + class_linker->FindClass(self, + "Ljava/util/logging/LogManager;", + ScopedNullHandle<mirror::ClassLoader>())); ASSERT_TRUE(log_manager_class.Get() != nullptr); ASSERT_TRUE(class_linker->EnsureInitialized(self, log_manager_class, true, true)); } @@ -1278,5 +1280,42 @@ TEST_F(UnstartedClassForNameTest, ClassForNameLongWithClassLoaderFail) { RunTest(runner, true, false); } +TEST_F(UnstartedRuntimeTest, ClassGetSignatureAnnotation) { + Thread* self = Thread::Current(); + ScopedObjectAccess soa(self); + + StackHandleScope<1> hs(self); + ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); + Handle<mirror::Class> list_class = hs.NewHandle( + class_linker->FindClass(self, + "Ljava/util/List;", + ScopedNullHandle<mirror::ClassLoader>())); + ASSERT_TRUE(list_class.Get() != nullptr); + ASSERT_TRUE(class_linker->EnsureInitialized(self, list_class, true, true)); + + JValue result; + ShadowFrame* shadow_frame = ShadowFrame::CreateDeoptimizedFrame(10, nullptr, nullptr, 0); + + shadow_frame->SetVRegReference(0, list_class.Get()); + UnstartedClassGetSignatureAnnotation(self, shadow_frame, &result, 0); + ASSERT_TRUE(result.GetL() != nullptr); + ASSERT_FALSE(self->IsExceptionPending()); + + ShadowFrame::DeleteDeoptimizedFrame(shadow_frame); + + ASSERT_TRUE(result.GetL()->IsObjectArray()); + ObjPtr<mirror::ObjectArray<mirror::Object>> array = + result.GetL()->AsObjectArray<mirror::Object>(); + std::ostringstream oss; + for (int32_t i = 0; i != array->GetLength(); ++i) { + ObjPtr<mirror::Object> elem = array->Get(i); + ASSERT_TRUE(elem != nullptr); + ASSERT_TRUE(elem->IsString()); + oss << elem->AsString()->ToModifiedUtf8(); + } + std::string output_string = oss.str(); + ASSERT_EQ(output_string, "<E:Ljava/lang/Object;>Ljava/lang/Object;Ljava/util/Collection<TE;>;"); +} + } // namespace interpreter } // namespace art diff --git a/runtime/method_handles.cc b/runtime/method_handles.cc index 6ecfd8c714..58c5d17d1c 100644 --- a/runtime/method_handles.cc +++ b/runtime/method_handles.cc @@ -419,6 +419,32 @@ static inline bool DoCallPolymorphic(ArtMethod* called_method, JValue* result, const mirror::MethodHandle::Kind handle_kind) REQUIRES_SHARED(Locks::mutator_lock_) { + // For virtual and interface methods ensure called_method points to + // the actual method to invoke. + if (handle_kind == mirror::MethodHandle::Kind::kInvokeVirtual || + handle_kind == mirror::MethodHandle::Kind::kInvokeInterface) { + uint32_t receiver_reg = is_range ? first_arg : args[0]; + ObjPtr<mirror::Object> receiver(shadow_frame.GetVRegReference(receiver_reg)); + if (IsCallerTransformer(callsite_type)) { + // The current receiver is an emulated stack frame, the method's + // receiver needs to be fetched from there as the emulated frame + // will be unpacked into a new frame. + receiver = ObjPtr<mirror::EmulatedStackFrame>::DownCast(receiver)->GetReceiver(); + } + + ObjPtr<mirror::Class> declaring_class(called_method->GetDeclaringClass()); + if (receiver == nullptr || receiver->GetClass() != declaring_class) { + // Verify that _vRegC is an object reference and of the type expected by + // the receiver. + if (!VerifyObjectIsClass(receiver, declaring_class)) { + DCHECK(self->IsExceptionPending()); + return false; + } + called_method = receiver->GetClass()->FindVirtualMethodForVirtualOrInterface( + called_method, kRuntimePointerSize); + } + } + // Compute method information. const DexFile::CodeItem* code_item = called_method->GetCodeItem(); @@ -502,24 +528,6 @@ static inline bool DoCallPolymorphic(ArtMethod* called_method, } } - // See TODO in DoInvokePolymorphic : We need to perform this dynamic, receiver - // based dispatch right before we perform the actual call, because the - // receiver isn't known very early. - if (handle_kind == mirror::MethodHandle::Kind::kInvokeVirtual || - handle_kind == mirror::MethodHandle::Kind::kInvokeInterface) { - ObjPtr<mirror::Object> receiver(new_shadow_frame->GetVRegReference(first_dest_reg)); - ObjPtr<mirror::Class> declaring_class(called_method->GetDeclaringClass()); - // Verify that _vRegC is an object reference and of the type expected by - // the receiver. - if (!VerifyObjectIsClass(receiver, declaring_class)) { - DCHECK(self->IsExceptionPending()); - return false; - } - - called_method = receiver->GetClass()->FindVirtualMethodForVirtualOrInterface( - called_method, kRuntimePointerSize); - } - PerformCall(self, code_item, shadow_frame.GetMethod(), first_dest_reg, new_shadow_frame, result); if (self->IsExceptionPending()) { return false; diff --git a/runtime/mirror/emulated_stack_frame.h b/runtime/mirror/emulated_stack_frame.h index ddd84a167d..76859ef1c8 100644 --- a/runtime/mirror/emulated_stack_frame.h +++ b/runtime/mirror/emulated_stack_frame.h @@ -62,6 +62,10 @@ class MANAGED EmulatedStackFrame : public Object { return GetFieldObject<MethodType>(OFFSET_OF_OBJECT_MEMBER(EmulatedStackFrame, type_)); } + mirror::Object* GetReceiver() REQUIRES_SHARED(Locks::mutator_lock_) { + return GetReferences()->Get(0); + } + static void SetClass(Class* klass) REQUIRES_SHARED(Locks::mutator_lock_); static void ResetClass() REQUIRES_SHARED(Locks::mutator_lock_); static void VisitRoots(RootVisitor* visitor) REQUIRES_SHARED(Locks::mutator_lock_); diff --git a/runtime/openjdkjvmti/ti_method.cc b/runtime/openjdkjvmti/ti_method.cc index 2ddd64a2bc..a6cfcc12bc 100644 --- a/runtime/openjdkjvmti/ti_method.cc +++ b/runtime/openjdkjvmti/ti_method.cc @@ -34,7 +34,9 @@ #include "art_jvmti.h" #include "art_method-inl.h" #include "base/enums.h" +#include "dex_file_annotations.h" #include "jni_internal.h" +#include "mirror/object_array-inl.h" #include "modifiers.h" #include "scoped_thread_state_change-inl.h" #include "thread-inl.h" @@ -139,6 +141,26 @@ jvmtiError MethodUtil::GetMethodName(jvmtiEnv* env, // TODO: Support generic signature. if (generic_ptr != nullptr) { *generic_ptr = nullptr; + if (!art_method->GetDeclaringClass()->IsProxyClass()) { + art::mirror::ObjectArray<art::mirror::String>* str_array = + art::annotations::GetSignatureAnnotationForMethod(art_method); + if (str_array != nullptr) { + std::ostringstream oss; + for (int32_t i = 0; i != str_array->GetLength(); ++i) { + oss << str_array->Get(i)->ToModifiedUtf8(); + } + std::string output_string = oss.str(); + unsigned char* tmp; + jvmtiError ret = CopyString(env, output_string.c_str(), &tmp); + if (ret != ERR(NONE)) { + return ret; + } + *generic_ptr = reinterpret_cast<char*>(tmp); + } else if (soa.Self()->IsExceptionPending()) { + // TODO: Should we report an error here? + soa.Self()->ClearException(); + } + } } // Everything is fine, release the buffers. diff --git a/test/021-string2/src/Main.java b/test/021-string2/src/Main.java index 5a43a4f23f..0dd82abf6f 100644 --- a/test/021-string2/src/Main.java +++ b/test/021-string2/src/Main.java @@ -16,6 +16,7 @@ import junit.framework.Assert; import java.lang.reflect.Method; +import java.util.Locale; /** * more string tests @@ -120,6 +121,12 @@ public class Main { testEqualsConstString(); testConstStringEquals(); + + // Regression tests for String.setCharAt() breaking string compression invariants. + Locale en_US = new Locale("en", "US"); + Assert.assertEquals("I", /* Small latin dotless i */ "\u0131".toUpperCase()); + Assert.assertEquals("abc", "a\u0131c".replace('\u0131', 'b')); + Assert.assertEquals("a\u0131c", "abc".replace('b', '\u0131')); } public static void testCompareToAndEquals() { diff --git a/test/910-methods/expected.txt b/test/910-methods/expected.txt index c913b3ffe5..e87929f00c 100644 --- a/test/910-methods/expected.txt +++ b/test/910-methods/expected.txt @@ -28,7 +28,7 @@ Location end: JVMTI_ERROR_NATIVE_METHOD Is native: true Is obsolete: false Is synthetic: false -[add, (Ljava/lang/Object;)Z, null] +[add, (Ljava/lang/Object;)Z, (TE;)Z] interface java.util.List 1025 Max locals: 0 diff --git a/test/956-methodhandles/src/Main.java b/test/956-methodhandles/src/Main.java index fc9f030559..cb06e4263e 100644 --- a/test/956-methodhandles/src/Main.java +++ b/test/956-methodhandles/src/Main.java @@ -183,15 +183,23 @@ public class Main { public String bar(); } - public static class BarSuper { + public static abstract class BarAbstractSuper { + public abstract String abstractSuperPublicMethod(); + } + + public static class BarSuper extends BarAbstractSuper { public String superPublicMethod() { return "superPublicMethod"; } - public String superProtectedMethod() { + protected String superProtectedMethod() { return "superProtectedMethod"; } + public String abstractSuperPublicMethod() { + return "abstractSuperPublicMethod"; + } + String superPackageMethod() { return "superPackageMethod"; } @@ -288,15 +296,19 @@ public class Main { System.out.println("Unexpected return value for BarImpl#bar: " + str); } - // TODO(narayan): Fix this case, we're using the wrong ArtMethod for the - // invoke resulting in a failing check in the interpreter. - // - // mh = MethodHandles.lookup().findVirtual(Bar.class, "bar", - // MethodType.methodType(String.class)); - // str = (String) mh.invoke(new BarImpl()); - // if (!"bar".equals(str)) { - // System.out.println("Unexpected return value for BarImpl#bar: " + str); - // } + mh = MethodHandles.lookup().findVirtual(Bar.class, "bar", + MethodType.methodType(String.class)); + str = (String) mh.invoke(new BarImpl()); + if (!"bar".equals(str)) { + System.out.println("Unexpected return value for BarImpl#bar: " + str); + } + + mh = MethodHandles.lookup().findVirtual(BarAbstractSuper.class, "abstractSuperPublicMethod", + MethodType.methodType(String.class)); + str = (String) mh.invoke(new BarImpl()); + if (!"abstractSuperPublicMethod".equals(str)) { + System.out.println("Unexpected return value for BarImpl#abstractSuperPublicMethod: " + str); + } // We should also be able to lookup public / protected / package methods in // the super class, given sufficient access privileges. diff --git a/test/run-test b/test/run-test index c926c115e2..d55ba771a2 100755 --- a/test/run-test +++ b/test/run-test @@ -80,7 +80,7 @@ fi # ANDROID_HOST_OUT is not set in a build environment. if [ -z "$ANDROID_HOST_OUT" ]; then - export ANDROID_HOST_OUT=${OUT_DIR:-$ANDROID_BUILD_TOP/out/}host/linux-x86 + export ANDROID_HOST_OUT=$ANDROID_BUILD_TOP/out/host/linux-x86 fi # If JACK_CLASSPATH is not set, assume it only contains core-libart. diff --git a/test/testrunner/testrunner.py b/test/testrunner/testrunner.py index 601acb63b5..5a6114e3cc 100755 --- a/test/testrunner/testrunner.py +++ b/test/testrunner/testrunner.py @@ -446,29 +446,34 @@ def run_test(command, test, test_variant, test_name): test_name: The name of the test along with the variants. """ global stop_testrunner - if is_test_disabled(test, test_variant): - test_skipped = True - else: - test_skipped = False - proc = subprocess.Popen(command.split(), stderr=subprocess.STDOUT, stdout=subprocess.PIPE) - script_output = proc.stdout.read().strip() - test_passed = not proc.wait() - - if not test_skipped: - if test_passed: - print_test_info(test_name, 'PASS') + try: + if is_test_disabled(test, test_variant): + test_skipped = True else: - failed_tests.append(test_name) - if not env.ART_TEST_KEEP_GOING: - stop_testrunner = True - print_test_info(test_name, 'FAIL', ('%s\n%s') % ( - command, script_output)) - elif not dry_run: - print_test_info(test_name, 'SKIP') - skipped_tests.append(test_name) - else: - print_test_info(test_name, '') - semaphore.release() + test_skipped = False + proc = subprocess.Popen(command.split(), stderr=subprocess.STDOUT, stdout=subprocess.PIPE) + script_output = proc.stdout.read().strip() + test_passed = not proc.wait() + + if not test_skipped: + if test_passed: + print_test_info(test_name, 'PASS') + else: + failed_tests.append(test_name) + if not env.ART_TEST_KEEP_GOING: + stop_testrunner = True + print_test_info(test_name, 'FAIL', ('%s\n%s') % ( + command, script_output)) + elif not dry_run: + print_test_info(test_name, 'SKIP') + skipped_tests.append(test_name) + else: + print_test_info(test_name, '') + except Exception, e: + failed_tests.append(test_name) + print_text(('%s\n%s\n') % (command, str(e))) + finally: + semaphore.release() def print_test_info(test_name, result, failed_test_info=""): @@ -485,6 +490,7 @@ def print_test_info(test_name, result, failed_test_info=""): command used to invoke the script. It doesn't override the failing test information in either of the cases. """ + global test_count info = '' if not verbose: @@ -493,48 +499,53 @@ def print_test_info(test_name, result, failed_test_info=""): # the console width. console_width = int(os.popen('stty size', 'r').read().split()[1]) info = '\r' + ' ' * console_width + '\r' - print_mutex.acquire() - test_count += 1 - percent = (test_count * 100) / total_test_count - progress_info = ('[ %d%% %d/%d ]') % ( - percent, - test_count, - total_test_count) - - if result == "FAIL": - info += ('%s %s %s\n%s\n') % ( - progress_info, - test_name, - COLOR_ERROR + 'FAIL' + COLOR_NORMAL, - failed_test_info) - else: - result_text = '' - if result == 'PASS': - result_text += COLOR_PASS + 'PASS' + COLOR_NORMAL - elif result == 'SKIP': - result_text += COLOR_SKIP + 'SKIP' + COLOR_NORMAL - - if verbose: - info += ('%s %s %s\n') % ( - progress_info, - test_name, - result_text) - else: - total_output_length = 2 # Two spaces - total_output_length += len(progress_info) - total_output_length += len(result) - allowed_test_length = console_width - total_output_length - test_name_len = len(test_name) - if allowed_test_length < test_name_len: - test_name = ('%s...%s') % ( - test_name[:(allowed_test_length - 3)/2], - test_name[-(allowed_test_length - 3)/2:]) - info += ('%s %s %s') % ( + try: + print_mutex.acquire() + test_count += 1 + percent = (test_count * 100) / total_test_count + progress_info = ('[ %d%% %d/%d ]') % ( + percent, + test_count, + total_test_count) + + if result == "FAIL": + info += ('%s %s %s\n%s\n') % ( progress_info, test_name, - result_text) - print_text(info) - print_mutex.release() + COLOR_ERROR + 'FAIL' + COLOR_NORMAL, + failed_test_info) + else: + result_text = '' + if result == 'PASS': + result_text += COLOR_PASS + 'PASS' + COLOR_NORMAL + elif result == 'SKIP': + result_text += COLOR_SKIP + 'SKIP' + COLOR_NORMAL + + if verbose: + info += ('%s %s %s\n') % ( + progress_info, + test_name, + result_text) + else: + total_output_length = 2 # Two spaces + total_output_length += len(progress_info) + total_output_length += len(result) + allowed_test_length = console_width - total_output_length + test_name_len = len(test_name) + if allowed_test_length < test_name_len: + test_name = ('%s...%s') % ( + test_name[:(allowed_test_length - 3)/2], + test_name[-(allowed_test_length - 3)/2:]) + info += ('%s %s %s') % ( + progress_info, + test_name, + result_text) + print_text(info) + except Exception, e: + print_text(('%s\n%s\n') % (test_name, str(e))) + failed_tests.append(test_name) + finally: + print_mutex.release() def get_disabled_test_info(): """Generate set of known failures. diff --git a/tools/libcore_failures.txt b/tools/libcore_failures.txt index dcef8c01c2..08abdb3713 100644 --- a/tools/libcore_failures.txt +++ b/tools/libcore_failures.txt @@ -105,12 +105,6 @@ names: ["org.apache.harmony.tests.java.lang.ProcessTest#test_getErrorStream"] }, { - description: "Short date format flag ignored for es_US locale.", - result: EXEC_FAILED, - name: "libcore.icu.DateIntervalFormatTest#test_formatDateInterval", - bug: 18619426 -}, -{ description: "Error decoding digital signature bytes.", result: EXEC_FAILED, name: "org.apache.harmony.security.tests.java.security.Signature2Test#test_verify$BII", @@ -134,12 +128,6 @@ names: ["org.apache.harmony.tests.java.lang.ProcessManagerTest#testEnvironment"] }, { - description: "Crypto failures", - result: EXEC_FAILED, - names: ["libcore.javax.crypto.CipherTest#testCipher_ShortBlock_Failure", - "libcore.javax.crypto.CipherTest#testCipher_Success"] -}, -{ description: "Flake when running with libartd.so or interpreter", result: EXEC_FAILED, bug:22106064, |