summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--compiler/optimizing/code_generator_x86.cc2
-rw-r--r--compiler/optimizing/code_generator_x86_64.cc2
-rw-r--r--disassembler/disassembler_x86.cc2
-rw-r--r--runtime/dex_file_annotations.cc92
-rw-r--r--runtime/gc/heap.cc8
-rw-r--r--runtime/gc/heap.h7
-rw-r--r--runtime/interpreter/unstarted_runtime.cc14
-rw-r--r--runtime/interpreter/unstarted_runtime_list.h1
-rw-r--r--runtime/interpreter/unstarted_runtime_test.cc45
-rw-r--r--runtime/method_handles.cc44
-rw-r--r--runtime/mirror/emulated_stack_frame.h4
-rw-r--r--runtime/openjdkjvmti/ti_method.cc22
-rw-r--r--test/021-string2/src/Main.java7
-rw-r--r--test/910-methods/expected.txt2
-rw-r--r--test/956-methodhandles/src/Main.java34
-rwxr-xr-xtest/run-test2
-rwxr-xr-xtest/testrunner/testrunner.py135
-rw-r--r--tools/libcore_failures.txt12
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,