Merge "Revert "Revert "Avoid adding region space bitmap to heap bitmap"""
diff --git a/runtime/asm_support.h b/runtime/asm_support.h
index 4a2e34f..c7a94a9 100644
--- a/runtime/asm_support.h
+++ b/runtime/asm_support.h
@@ -246,7 +246,7 @@
ADD_TEST_EQ(MIRROR_STRING_VALUE_OFFSET, art::mirror::String::ValueOffset().Int32Value())
// String compression feature.
-#define STRING_COMPRESSION_FEATURE 1
+#define STRING_COMPRESSION_FEATURE 0
ADD_TEST_EQ(STRING_COMPRESSION_FEATURE, art::mirror::kUseStringCompression);
#if defined(__cplusplus)
diff --git a/runtime/image.cc b/runtime/image.cc
index 1acfcf5..54b099e 100644
--- a/runtime/image.cc
+++ b/runtime/image.cc
@@ -25,7 +25,7 @@
namespace art {
const uint8_t ImageHeader::kImageMagic[] = { 'a', 'r', 't', '\n' };
-const uint8_t ImageHeader::kImageVersion[] = { '0', '3', '7', '\0' }; // Enable string compression.
+const uint8_t ImageHeader::kImageVersion[] = { '0', '3', '6', '\0' }; // Erroneous resolved class.
ImageHeader::ImageHeader(uint32_t image_begin,
uint32_t image_size,
diff --git a/runtime/interpreter/unstarted_runtime.cc b/runtime/interpreter/unstarted_runtime.cc
index 66f14b9..fc21945 100644
--- a/runtime/interpreter/unstarted_runtime.cc
+++ b/runtime/interpreter/unstarted_runtime.cc
@@ -175,56 +175,61 @@
return param->AsString();
}
-void UnstartedRuntime::UnstartedClassForName(
- Thread* self, ShadowFrame* shadow_frame, JValue* result, size_t arg_offset) {
+void UnstartedRuntime::UnstartedClassForNameCommon(Thread* self,
+ ShadowFrame* shadow_frame,
+ JValue* result,
+ size_t arg_offset,
+ bool long_form,
+ const char* caller) {
mirror::String* class_name = GetClassName(self, shadow_frame, arg_offset);
if (class_name == nullptr) {
return;
}
+ bool initialize_class;
+ mirror::ClassLoader* class_loader;
+ if (long_form) {
+ initialize_class = shadow_frame->GetVReg(arg_offset + 1) != 0;
+ class_loader = down_cast<mirror::ClassLoader*>(shadow_frame->GetVRegReference(arg_offset + 2));
+ } else {
+ initialize_class = true;
+ // TODO: This is really only correct for the boot classpath, and for robustness we should
+ // check the caller.
+ class_loader = nullptr;
+ }
+
+ ScopedObjectAccessUnchecked soa(self);
+ if (class_loader != nullptr && !ClassLinker::IsBootClassLoader(soa, class_loader)) {
+ AbortTransactionOrFail(self,
+ "Only the boot classloader is supported: %s",
+ mirror::Object::PrettyTypeOf(class_loader).c_str());
+ return;
+ }
+
StackHandleScope<1> hs(self);
Handle<mirror::String> h_class_name(hs.NewHandle(class_name));
UnstartedRuntimeFindClass(self,
h_class_name,
ScopedNullHandle<mirror::ClassLoader>(),
result,
- "Class.forName",
- true,
+ caller,
+ initialize_class,
false);
CheckExceptionGenerateClassNotFound(self);
}
+void UnstartedRuntime::UnstartedClassForName(
+ Thread* self, ShadowFrame* shadow_frame, JValue* result, size_t arg_offset) {
+ UnstartedClassForNameCommon(self, shadow_frame, result, arg_offset, false, "Class.forName");
+}
+
void UnstartedRuntime::UnstartedClassForNameLong(
Thread* self, ShadowFrame* shadow_frame, JValue* result, size_t arg_offset) {
- mirror::String* class_name = GetClassName(self, shadow_frame, arg_offset);
- if (class_name == nullptr) {
- return;
- }
- bool initialize_class = shadow_frame->GetVReg(arg_offset + 1) != 0;
- mirror::ClassLoader* class_loader =
- down_cast<mirror::ClassLoader*>(shadow_frame->GetVRegReference(arg_offset + 2));
- StackHandleScope<2> hs(self);
- Handle<mirror::String> h_class_name(hs.NewHandle(class_name));
- Handle<mirror::ClassLoader> h_class_loader(hs.NewHandle(class_loader));
- UnstartedRuntimeFindClass(self, h_class_name, h_class_loader, result, "Class.forName",
- initialize_class, false);
- CheckExceptionGenerateClassNotFound(self);
+ UnstartedClassForNameCommon(self, shadow_frame, result, arg_offset, true, "Class.forName");
}
void UnstartedRuntime::UnstartedClassClassForName(
Thread* self, ShadowFrame* shadow_frame, JValue* result, size_t arg_offset) {
- mirror::String* class_name = GetClassName(self, shadow_frame, arg_offset);
- if (class_name == nullptr) {
- return;
- }
- bool initialize_class = shadow_frame->GetVReg(arg_offset + 1) != 0;
- mirror::ClassLoader* class_loader =
- down_cast<mirror::ClassLoader*>(shadow_frame->GetVRegReference(arg_offset + 2));
- StackHandleScope<2> hs(self);
- Handle<mirror::String> h_class_name(hs.NewHandle(class_name));
- Handle<mirror::ClassLoader> h_class_loader(hs.NewHandle(class_loader));
- UnstartedRuntimeFindClass(self, h_class_name, h_class_loader, result, "Class.classForName",
- initialize_class, false);
- CheckExceptionGenerateClassNotFound(self);
+ UnstartedClassForNameCommon(self, shadow_frame, result, arg_offset, true, "Class.classForName");
}
void UnstartedRuntime::UnstartedClassNewInstance(
diff --git a/runtime/interpreter/unstarted_runtime.h b/runtime/interpreter/unstarted_runtime.h
index 3f36a27..bc9ead8 100644
--- a/runtime/interpreter/unstarted_runtime.h
+++ b/runtime/interpreter/unstarted_runtime.h
@@ -89,6 +89,13 @@
#undef UNSTARTED_RUNTIME_JNI_LIST
#undef UNSTARTED_JNI
+ static void UnstartedClassForNameCommon(Thread* self,
+ ShadowFrame* shadow_frame,
+ JValue* result,
+ size_t arg_offset,
+ bool long_form,
+ const char* caller) REQUIRES_SHARED(Locks::mutator_lock_);
+
static void InitializeInvokeHandlers();
static void InitializeJNIHandlers();
diff --git a/runtime/interpreter/unstarted_runtime_test.cc b/runtime/interpreter/unstarted_runtime_test.cc
index 98a17e4..3a0d0e7 100644
--- a/runtime/interpreter/unstarted_runtime_test.cc
+++ b/runtime/interpreter/unstarted_runtime_test.cc
@@ -1084,5 +1084,199 @@
ASSERT_TRUE(class_linker->EnsureInitialized(self, log_manager_class, true, true));
}
+class UnstartedClassForNameTest : public UnstartedRuntimeTest {
+ public:
+ template <typename T>
+ void RunTest(T& runner, bool in_transaction, bool should_succeed) {
+ Thread* self = Thread::Current();
+ ScopedObjectAccess soa(self);
+
+ // Ensure that Class is initialized.
+ {
+ ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+ StackHandleScope<1> hs(self);
+ Handle<mirror::Class> h_class = hs.NewHandle(mirror::Class::GetJavaLangClass());
+ CHECK(class_linker->EnsureInitialized(self, h_class, true, true));
+ }
+
+ // A selection of classes from different core classpath components.
+ constexpr const char* kTestCases[] = {
+ "java.net.CookieManager", // From libcore.
+ "dalvik.system.ClassExt", // From libart.
+ };
+
+ if (in_transaction) {
+ // For transaction mode, we cannot load any classes, as the pre-fence initialization of
+ // classes isn't transactional. Load them ahead of time.
+ ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+ for (const char* name : kTestCases) {
+ class_linker->FindClass(self,
+ DotToDescriptor(name).c_str(),
+ ScopedNullHandle<mirror::ClassLoader>());
+ CHECK(!self->IsExceptionPending()) << self->GetException()->Dump();
+ }
+ }
+
+ if (!should_succeed) {
+ // Negative test. In general, currentThread should fail (as we should not leak a peer that will
+ // be recreated at runtime).
+ PrepareForAborts();
+ }
+
+ JValue result;
+ ShadowFrame* shadow_frame = ShadowFrame::CreateDeoptimizedFrame(10, nullptr, nullptr, 0);
+
+ for (const char* name : kTestCases) {
+ mirror::String* name_string = mirror::String::AllocFromModifiedUtf8(self, name);
+ CHECK(name_string != nullptr);
+
+ Transaction transaction;
+ if (in_transaction) {
+ Runtime::Current()->EnterTransactionMode(&transaction);
+ }
+ CHECK(!self->IsExceptionPending());
+
+ runner(self, shadow_frame, name_string, &result);
+
+ if (in_transaction) {
+ Runtime::Current()->ExitTransactionMode();
+ }
+
+ if (should_succeed) {
+ CHECK(!self->IsExceptionPending()) << name << " " << self->GetException()->Dump();
+ CHECK(result.GetL() != nullptr) << name;
+ } else {
+ CHECK(self->IsExceptionPending()) << name;
+ if (in_transaction) {
+ ASSERT_TRUE(transaction.IsAborted());
+ }
+ self->ClearException();
+ }
+ }
+
+ ShadowFrame::DeleteDeoptimizedFrame(shadow_frame);
+ }
+
+ mirror::ClassLoader* GetBootClassLoader() REQUIRES_SHARED(Locks::mutator_lock_) {
+ Thread* self = Thread::Current();
+ StackHandleScope<2> hs(self);
+ MutableHandle<mirror::ClassLoader> boot_cp = hs.NewHandle<mirror::ClassLoader>(nullptr);
+
+ {
+ ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+
+ // Create the fake boot classloader. Any instance is fine, they are technically interchangeable.
+ Handle<mirror::Class> boot_cp_class = hs.NewHandle(
+ class_linker->FindClass(self,
+ "Ljava/lang/BootClassLoader;",
+ ScopedNullHandle<mirror::ClassLoader>()));
+ CHECK(boot_cp_class != nullptr);
+ CHECK(class_linker->EnsureInitialized(self, boot_cp_class, true, true));
+
+ boot_cp.Assign(boot_cp_class->AllocObject(self)->AsClassLoader());
+ CHECK(boot_cp != nullptr);
+
+ ArtMethod* boot_cp_init = boot_cp_class->FindDeclaredDirectMethod(
+ "<init>", "()V", class_linker->GetImagePointerSize());
+ CHECK(boot_cp_init != nullptr);
+
+ JValue result;
+ ShadowFrame* shadow_frame = ShadowFrame::CreateDeoptimizedFrame(10, nullptr, boot_cp_init, 0);
+ shadow_frame->SetVRegReference(0, boot_cp.Get());
+
+ // create instruction data for invoke-direct {v0} of method with fake index
+ uint16_t inst_data[3] = { 0x1070, 0x0000, 0x0010 };
+ const Instruction* inst = Instruction::At(inst_data);
+
+ interpreter::DoCall<false, false>(boot_cp_init,
+ self,
+ *shadow_frame,
+ inst,
+ inst_data[0],
+ &result);
+ CHECK(!self->IsExceptionPending());
+
+ ShadowFrame::DeleteDeoptimizedFrame(shadow_frame);
+ }
+
+ return boot_cp.Get();
+ }
+};
+
+TEST_F(UnstartedClassForNameTest, ClassForName) {
+ auto runner = [](Thread* self, ShadowFrame* shadow_frame, mirror::String* name, JValue* result)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ shadow_frame->SetVRegReference(0, name);
+ UnstartedClassForName(self, shadow_frame, result, 0);
+ };
+ RunTest(runner, false, true);
+}
+
+TEST_F(UnstartedClassForNameTest, ClassForNameLong) {
+ auto runner = [](Thread* self, ShadowFrame* shadow_frame, mirror::String* name, JValue* result)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ shadow_frame->SetVRegReference(0, name);
+ shadow_frame->SetVReg(1, 0);
+ shadow_frame->SetVRegReference(2, nullptr);
+ UnstartedClassForNameLong(self, shadow_frame, result, 0);
+ };
+ RunTest(runner, false, true);
+}
+
+TEST_F(UnstartedClassForNameTest, ClassForNameLongWithClassLoader) {
+ Thread* self = Thread::Current();
+ ScopedObjectAccess soa(self);
+
+ StackHandleScope<1> hs(self);
+ Handle<mirror::ClassLoader> boot_cp = hs.NewHandle(GetBootClassLoader());
+
+ auto runner = [&](Thread* th, ShadowFrame* shadow_frame, mirror::String* name, JValue* result)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ shadow_frame->SetVRegReference(0, name);
+ shadow_frame->SetVReg(1, 0);
+ shadow_frame->SetVRegReference(2, boot_cp.Get());
+ UnstartedClassForNameLong(th, shadow_frame, result, 0);
+ };
+ RunTest(runner, false, true);
+}
+
+TEST_F(UnstartedClassForNameTest, ClassForNameLongWithClassLoaderTransaction) {
+ Thread* self = Thread::Current();
+ ScopedObjectAccess soa(self);
+
+ StackHandleScope<1> hs(self);
+ Handle<mirror::ClassLoader> boot_cp = hs.NewHandle(GetBootClassLoader());
+
+ auto runner = [&](Thread* th, ShadowFrame* shadow_frame, mirror::String* name, JValue* result)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ shadow_frame->SetVRegReference(0, name);
+ shadow_frame->SetVReg(1, 0);
+ shadow_frame->SetVRegReference(2, boot_cp.Get());
+ UnstartedClassForNameLong(th, shadow_frame, result, 0);
+ };
+ RunTest(runner, true, true);
+}
+
+TEST_F(UnstartedClassForNameTest, ClassForNameLongWithClassLoaderFail) {
+ Thread* self = Thread::Current();
+ ScopedObjectAccess soa(self);
+
+ StackHandleScope<2> hs(self);
+ ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+ jobject path_jobj = class_linker->CreatePathClassLoader(self, {});
+ ASSERT_TRUE(path_jobj != nullptr);
+ Handle<mirror::ClassLoader> path_cp = hs.NewHandle<mirror::ClassLoader>(
+ self->DecodeJObject(path_jobj)->AsClassLoader());
+
+ auto runner = [&](Thread* th, ShadowFrame* shadow_frame, mirror::String* name, JValue* result)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ shadow_frame->SetVRegReference(0, name);
+ shadow_frame->SetVReg(1, 0);
+ shadow_frame->SetVRegReference(2, path_cp.Get());
+ UnstartedClassForNameLong(th, shadow_frame, result, 0);
+ };
+ RunTest(runner, true, false);
+}
+
} // namespace interpreter
} // namespace art
diff --git a/runtime/mirror/string.h b/runtime/mirror/string.h
index 08296c6..38f6dd4 100644
--- a/runtime/mirror/string.h
+++ b/runtime/mirror/string.h
@@ -32,7 +32,7 @@
namespace mirror {
// String Compression
-static constexpr bool kUseStringCompression = true;
+static constexpr bool kUseStringCompression = false;
enum class StringCompressionFlag : uint32_t {
kCompressed = 0u,
kUncompressed = 1u
diff --git a/runtime/openjdkjvmti/ti_class.cc b/runtime/openjdkjvmti/ti_class.cc
index 7ca233f..a8a0ded 100644
--- a/runtime/openjdkjvmti/ti_class.cc
+++ b/runtime/openjdkjvmti/ti_class.cc
@@ -41,6 +41,7 @@
#include "class_table-inl.h"
#include "class_linker.h"
#include "common_throws.h"
+#include "dex_file_annotations.h"
#include "events-inl.h"
#include "gc/heap.h"
#include "gc_root.h"
@@ -50,6 +51,7 @@
#include "mirror/array-inl.h"
#include "mirror/class-inl.h"
#include "mirror/class_ext.h"
+#include "mirror/object_array-inl.h"
#include "mirror/object_reference.h"
#include "mirror/object-inl.h"
#include "mirror/reference.h"
@@ -685,9 +687,30 @@
*signature_ptr = reinterpret_cast<char*>(tmp);
}
- // TODO: Support generic signature.
if (generic_ptr != nullptr) {
*generic_ptr = nullptr;
+ if (!klass->IsProxyClass() && klass->GetDexCache() != nullptr) {
+ art::StackHandleScope<1> hs(soa.Self());
+ art::Handle<art::mirror::Class> h_klass = hs.NewHandle(klass);
+ art::mirror::ObjectArray<art::mirror::String>* str_array =
+ art::annotations::GetSignatureAnnotationForClass(h_klass);
+ 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/runtime/openjdkjvmti/ti_field.cc b/runtime/openjdkjvmti/ti_field.cc
index a762830..131e6c3 100644
--- a/runtime/openjdkjvmti/ti_field.cc
+++ b/runtime/openjdkjvmti/ti_field.cc
@@ -34,7 +34,9 @@
#include "art_jvmti.h"
#include "art_field-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"
@@ -91,6 +93,26 @@
// TODO: Support generic signature.
if (generic_ptr != nullptr) {
*generic_ptr = nullptr;
+ if (!art_field->GetDeclaringClass()->IsProxyClass()) {
+ art::mirror::ObjectArray<art::mirror::String>* str_array =
+ art::annotations::GetSignatureAnnotationForField(art_field);
+ 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/912-classes/expected.txt b/test/912-classes/expected.txt
index 328216b..e932b20 100644
--- a/test/912-classes/expected.txt
+++ b/test/912-classes/expected.txt
@@ -1,10 +1,10 @@
[Ljava/lang/Object;, null]
1
-[Ljava/lang/String;, null]
+[Ljava/lang/String;, Ljava/lang/Object;Ljava/io/Serializable;Ljava/lang/Comparable<Ljava/lang/String;>;Ljava/lang/CharSequence;]
11
[Ljava/lang/Math;, null]
11
-[Ljava/util/List;, null]
+[Ljava/util/List;, <E:Ljava/lang/Object;>Ljava/lang/Object;Ljava/util/Collection<TE;>;]
601
[L$Proxy0;, null]
11
diff --git a/test/918-fields/expected.txt b/test/918-fields/expected.txt
index 39d3e70..1a1209c 100644
--- a/test/918-fields/expected.txt
+++ b/test/918-fields/expected.txt
@@ -14,3 +14,7 @@
interface Main$Bar
25
false
+[generics, Ljava/lang/Object;, TT;]
+class Main$Generics
+0
+false
diff --git a/test/918-fields/src/Main.java b/test/918-fields/src/Main.java
index 3ba535b..ad0d0c5 100644
--- a/test/918-fields/src/Main.java
+++ b/test/918-fields/src/Main.java
@@ -27,6 +27,7 @@
testField(Integer.class, "value");
testField(Foo.class, "this$0");
testField(Bar.class, "VAL");
+ testField(Generics.class, "generics");
}
private static void testField(Class<?> base, String fieldName)
@@ -65,4 +66,8 @@
private static interface Bar {
public static int VAL = 1;
}
+
+ private static class Generics<T> {
+ T generics;
+ }
}
diff --git a/test/Android.run-test.mk b/test/Android.run-test.mk
index 1938b92..c14a0b2 100644
--- a/test/Android.run-test.mk
+++ b/test/Android.run-test.mk
@@ -898,12 +898,24 @@
endif
endef
+COMPILER_TYPES_2 := optimizing
+COMPILER_TYPES_2 += interpreter
+COMPILER_TYPES_2 += jit
+COMPILER_TYPES_2 += regalloc_gc
+COMPILER_TYPES_2 += interp-ac
+ALL_ADDRESS_SIZES_2 := 32 64
+IMAGE_TYPES_2 := picimage
+IMAGE_TYPES_2 += no-image
+IMAGE_TYPES_2 += npicimage
+IMAGE_TYPES_2 += multinpicimage
+IMAGE_TYPES_2 += multipicimage
+
# Add core image dependencies required for given target - HOST or TARGET,
# IMAGE_TYPE, COMPILER_TYPE and ADDRESS_SIZE to the prereq_rules.
$(foreach target, $(TARGET_TYPES), \
- $(foreach image, $(IMAGE_TYPES), \
- $(foreach compiler, $(COMPILER_TYPES), \
- $(foreach address_size, $(ALL_ADDRESS_SIZES), $(eval \
+ $(foreach image, $(IMAGE_TYPES_2), \
+ $(foreach compiler, $(COMPILER_TYPES_2), \
+ $(foreach address_size, $(ALL_ADDRESS_SIZES_2), $(eval \
$(call core-image-dependencies,$(target),$(image),$(compiler),$(address_size)))))))
test-art-host-run-test-dependencies : $(host_prereq_rules)
diff --git a/test/testrunner/testrunner.py b/test/testrunner/testrunner.py
index a5bfcff..f48bf76 100755
--- a/test/testrunner/testrunner.py
+++ b/test/testrunner/testrunner.py
@@ -837,15 +837,13 @@
while threading.active_count() > 1:
time.sleep(0.1)
print_analysis()
- if failed_tests:
- sys.exit(1)
- sys.exit(0)
- except SystemExit:
- pass
except Exception, e:
print_analysis()
print_text(str(e))
sys.exit(1)
+ if failed_tests:
+ sys.exit(1)
+ sys.exit(0)
if __name__ == '__main__':
main()