diff options
51 files changed, 1086 insertions, 140 deletions
diff --git a/Android.mk b/Android.mk index 97a82e2077..35cb641510 100644 --- a/Android.mk +++ b/Android.mk @@ -98,16 +98,22 @@ include $(art_path)/sigchainlib/Android.mk ART_HOST_DEPENDENCIES := \ $(ART_HOST_EXECUTABLES) \ $(HOST_OUT_JAVA_LIBRARIES)/core-libart-hostdex.jar \ - $(ART_HOST_OUT_SHARED_LIBRARIES)/libjavacore$(ART_HOST_SHLIB_EXTENSION) + $(HOST_OUT_JAVA_LIBRARIES)/core-oj-hostdex.jar \ + $(ART_HOST_OUT_SHARED_LIBRARIES)/libjavacore$(ART_HOST_SHLIB_EXTENSION) \ + $(ART_HOST_OUT_SHARED_LIBRARIES)/libopenjdk$(ART_HOST_SHLIB_EXTENSION) ART_TARGET_DEPENDENCIES := \ $(ART_TARGET_EXECUTABLES) \ $(TARGET_OUT_JAVA_LIBRARIES)/core-libart.jar \ - $(TARGET_OUT_SHARED_LIBRARIES)/libjavacore.so + $(TARGET_OUT_JAVA_LIBRARIES)/core-oj.jar \ + $(TARGET_OUT_SHARED_LIBRARIES)/libjavacore.so \ + $(TARGET_OUT_SHARED_LIBRARIES)/libopenjdk.so ifdef TARGET_2ND_ARCH ART_TARGET_DEPENDENCIES += $(2ND_TARGET_OUT_SHARED_LIBRARIES)/libjavacore.so +ART_TARGET_DEPENDENCIES += $(2ND_TARGET_OUT_SHARED_LIBRARIES)/libopenjdk.so endif ifdef HOST_2ND_ARCH ART_HOST_DEPENDENCIES += $(2ND_HOST_OUT_SHARED_LIBRARIES)/libjavacore.so +ART_HOST_DEPENDENCIES += $(2ND_HOST_OUT_SHARED_LIBRARIES)/libopenjdk.so endif ######################################################################## diff --git a/build/Android.common_path.mk b/build/Android.common_path.mk index c53479c8b0..7fd2a5acb6 100644 --- a/build/Android.common_path.mk +++ b/build/Android.common_path.mk @@ -80,7 +80,7 @@ HOST_CORE_IMG_LOCATION := $(HOST_OUT_JAVA_LIBRARIES)/core.art TARGET_CORE_IMG_LOCATION := $(ART_TARGET_TEST_OUT)/core.art # Jar files for core.art. -TARGET_CORE_JARS := core-libart conscrypt okhttp bouncycastle +TARGET_CORE_JARS := core-oj core-libart conscrypt okhttp bouncycastle HOST_CORE_JARS := $(addsuffix -hostdex,$(TARGET_CORE_JARS)) HOST_CORE_DEX_LOCATIONS := $(foreach jar,$(HOST_CORE_JARS), $(HOST_OUT_JAVA_LIBRARIES)/$(jar).jar) @@ -91,9 +91,9 @@ TARGET_CORE_DEX_FILES := $(foreach jar,$(TARGET_CORE_JARS),$(call intermediates- ifeq ($(ANDROID_COMPILE_WITH_JACK),true) # Classpath for Jack compilation: we only need core-libart. -HOST_JACK_CLASSPATH_DEPENDENCIES := $(call intermediates-dir-for,JAVA_LIBRARIES,core-libart-hostdex,t,COMMON)/classes.jack -HOST_JACK_CLASSPATH := $(foreach dep,$(HOST_JACK_CLASSPATH_DEPENDENCIES),$(abspath $(dep))) -TARGET_JACK_CLASSPATH_DEPENDENCIES := $(call intermediates-dir-for,JAVA_LIBRARIES,core-libart, ,COMMON)/classes.jack -TARGET_JACK_CLASSPATH := $(foreach dep,$(TARGET_JACK_CLASSPATH_DEPENDENCIES),$(abspath $(dep))) +HOST_JACK_CLASSPATH_DEPENDENCIES := $(call intermediates-dir-for,JAVA_LIBRARIES,core-oj-hostdex,t,COMMON)/classes.jack $(call intermediates-dir-for,JAVA_LIBRARIES,core-libart-hostdex,t,COMMON)/classes.jack +HOST_JACK_CLASSPATH := $(abspath $(call intermediates-dir-for,JAVA_LIBRARIES,core-oj-hostdex,t,COMMON)/classes.jack):$(abspath $(call intermediates-dir-for,JAVA_LIBRARIES,core-libart-hostdex,t,COMMON)/classes.jack) +TARGET_JACK_CLASSPATH_DEPENDENCIES := $(call intermediates-dir-for,JAVA_LIBRARIES,core-oj, ,COMMON)/classes.jack $(call intermediates-dir-for,JAVA_LIBRARIES,core-libart, ,COMMON)/classes.jack +TARGET_JACK_CLASSPATH := $(abspath $(call intermediates-dir-for,JAVA_LIBRARIES,core-oj, ,COMMON)/classes.jack):$(abspath $(call intermediates-dir-for,JAVA_LIBRARIES,core-libart, ,COMMON)/classes.jack) endif endif # ART_ANDROID_COMMON_PATH_MK diff --git a/build/Android.gtest.mk b/build/Android.gtest.mk index 291a69de10..08730d0654 100644 --- a/build/Android.gtest.mk +++ b/build/Android.gtest.mk @@ -441,7 +441,9 @@ define define-art-gtest-rule-target $(foreach file,$(ART_GTEST_$(1)_DEX_DEPS),$(ART_TEST_TARGET_GTEST_$(file)_DEX)) \ $$(ART_TARGET_NATIVETEST_OUT)/$$(TARGET_$(2)ARCH)/$(1) \ $$($(2)TARGET_OUT_SHARED_LIBRARIES)/libjavacore.so \ - $$(TARGET_OUT_JAVA_LIBRARIES)/core-libart.jar + $$($(2)TARGET_OUT_SHARED_LIBRARIES)/libopenjdk.so \ + $$(TARGET_OUT_JAVA_LIBRARIES)/core-libart.jar \ + $$(TARGET_OUT_JAVA_LIBRARIES)/core-oj.jar .PHONY: $$(gtest_rule) $$(gtest_rule): test-art-target-sync @@ -483,6 +485,7 @@ define define-art-gtest-rule-host # Dependencies for all host gtests. gtest_deps := $$(HOST_CORE_DEX_LOCATIONS) \ $$($(2)ART_HOST_OUT_SHARED_LIBRARIES)/libjavacore$$(ART_HOST_SHLIB_EXTENSION) \ + $$($(2)ART_HOST_OUT_SHARED_LIBRARIES)/libopenjdk$$(ART_HOST_SHLIB_EXTENSION) \ $$(gtest_exe) \ $$(ART_GTEST_$(1)_HOST_DEPS) \ $(foreach file,$(ART_GTEST_$(1)_DEX_DEPS),$(ART_TEST_HOST_GTEST_$(file)_DEX)) diff --git a/compiler/driver/compiler_driver_test.cc b/compiler/driver/compiler_driver_test.cc index f8de9fa4a1..2e43c2c71a 100644 --- a/compiler/driver/compiler_driver_test.cc +++ b/compiler/driver/compiler_driver_test.cc @@ -145,7 +145,7 @@ TEST_F(CompilerDriverTest, DISABLED_LARGE_CompileDexLibCore) { // TODO: check that all Method::GetCode() values are non-null } -TEST_F(CompilerDriverTest, AbstractMethodErrorStub) { +TEST_F(CompilerDriverTest, DISABLED_AbstractMethodErrorStub) { TEST_DISABLED_FOR_HEAP_REFERENCE_POISONING_WITH_QUICK(); TEST_DISABLED_FOR_READ_BARRIER_WITH_QUICK(); TEST_DISABLED_FOR_READ_BARRIER_WITH_OPTIMIZING_FOR_UNSUPPORTED_INSTRUCTION_SETS(); diff --git a/compiler/image_test.cc b/compiler/image_test.cc index 15812dc3f3..5afe2db27f 100644 --- a/compiler/image_test.cc +++ b/compiler/image_test.cc @@ -181,7 +181,7 @@ void ImageTest::TestWriteRead(ImageHeader::StorageMode storage_mode) { java_lang_dex_file_ = nullptr; MemMap::Init(); - std::unique_ptr<const DexFile> dex(LoadExpectSingleDexFile(GetLibCoreDexFileName().c_str())); + std::unique_ptr<const DexFile> dex(LoadExpectSingleDexFile(GetLibCoreDexFileNames()[0].c_str())); RuntimeOptions options; std::string image("-Ximage:"); diff --git a/compiler/oat_test.cc b/compiler/oat_test.cc index eea52045cc..8865ea2243 100644 --- a/compiler/oat_test.cc +++ b/compiler/oat_test.cc @@ -199,7 +199,7 @@ TEST_F(OatTest, WriteRead) { ASSERT_TRUE(oat_file.get() != nullptr) << error_msg; const OatHeader& oat_header = oat_file->GetOatHeader(); ASSERT_TRUE(oat_header.IsValid()); - ASSERT_EQ(1U, oat_header.GetDexFileCount()); // core + ASSERT_EQ(class_linker->GetBootClassPath().size(), oat_header.GetDexFileCount()); // core ASSERT_EQ(42U, oat_header.GetImageFileLocationOatChecksum()); ASSERT_EQ(4096U, oat_header.GetImageFileLocationOatDataBegin()); ASSERT_EQ("lue.art", std::string(oat_header.GetStoreValueByKey(OatHeader::kImageLocationKey))); diff --git a/dexdump/dexdump_test.cc b/dexdump/dexdump_test.cc index 4230cb26b7..9819233a32 100644 --- a/dexdump/dexdump_test.cc +++ b/dexdump/dexdump_test.cc @@ -37,7 +37,7 @@ class DexDumpTest : public CommonRuntimeTest { virtual void SetUp() { CommonRuntimeTest::SetUp(); // Dogfood our own lib core dex file. - dex_file_ = GetLibCoreDexFileName(); + dex_file_ = GetLibCoreDexFileNames()[0]; } // Runs test with given arguments. diff --git a/dexlist/dexlist_test.cc b/dexlist/dexlist_test.cc index 82179dea95..9a65ba647c 100644 --- a/dexlist/dexlist_test.cc +++ b/dexlist/dexlist_test.cc @@ -37,7 +37,7 @@ class DexListTest : public CommonRuntimeTest { virtual void SetUp() { CommonRuntimeTest::SetUp(); // Dogfood our own lib core dex file. - dex_file_ = GetLibCoreDexFileName(); + dex_file_ = GetLibCoreDexFileNames()[0]; } // Runs test with given arguments. diff --git a/runtime/Android.mk b/runtime/Android.mk index 40961179d3..d97e1cdef5 100644 --- a/runtime/Android.mk +++ b/runtime/Android.mk @@ -156,6 +156,7 @@ LIBART_COMMON_SRC_FILES := \ native/libcore_util_CharsetUtils.cc \ native/org_apache_harmony_dalvik_ddmc_DdmServer.cc \ native/org_apache_harmony_dalvik_ddmc_DdmVmInternal.cc \ + native/OpenjdkJvm.cc \ native/sun_misc_Unsafe.cc \ oat.cc \ oat_file.cc \ diff --git a/runtime/asm_support.h b/runtime/asm_support.h index c86614c0fd..7ec06567d2 100644 --- a/runtime/asm_support.h +++ b/runtime/asm_support.h @@ -160,16 +160,16 @@ ADD_TEST_EQ(MIRROR_OBJECT_LOCK_WORD_OFFSET, art::mirror::Object::MonitorOffset() ADD_TEST_EQ(size_t(MIRROR_OBJECT_HEADER_SIZE), sizeof(art::mirror::Object)) // Offsets within java.lang.Class. -#define MIRROR_CLASS_COMPONENT_TYPE_OFFSET (4 + MIRROR_OBJECT_HEADER_SIZE) +#define MIRROR_CLASS_COMPONENT_TYPE_OFFSET (8 + MIRROR_OBJECT_HEADER_SIZE) ADD_TEST_EQ(MIRROR_CLASS_COMPONENT_TYPE_OFFSET, art::mirror::Class::ComponentTypeOffset().Int32Value()) -#define MIRROR_CLASS_ACCESS_FLAGS_OFFSET (72 + MIRROR_OBJECT_HEADER_SIZE) +#define MIRROR_CLASS_ACCESS_FLAGS_OFFSET (36 + MIRROR_OBJECT_HEADER_SIZE) ADD_TEST_EQ(MIRROR_CLASS_ACCESS_FLAGS_OFFSET, art::mirror::Class::AccessFlagsOffset().Int32Value()) -#define MIRROR_CLASS_OBJECT_SIZE_OFFSET (104 + MIRROR_OBJECT_HEADER_SIZE) +#define MIRROR_CLASS_OBJECT_SIZE_OFFSET (108 + MIRROR_OBJECT_HEADER_SIZE) ADD_TEST_EQ(MIRROR_CLASS_OBJECT_SIZE_OFFSET, art::mirror::Class::ObjectSizeOffset().Int32Value()) -#define MIRROR_CLASS_STATUS_OFFSET (116 + MIRROR_OBJECT_HEADER_SIZE) +#define MIRROR_CLASS_STATUS_OFFSET (120 + MIRROR_OBJECT_HEADER_SIZE) ADD_TEST_EQ(MIRROR_CLASS_STATUS_OFFSET, art::mirror::Class::StatusOffset().Int32Value()) diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc index f5085ed417..d828838268 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -3434,7 +3434,7 @@ ArtMethod* ClassLinker::FindMethodForProxy(mirror::Class* proxy_class, ArtMethod void ClassLinker::CreateProxyConstructor(Handle<mirror::Class> klass, ArtMethod* out) { // Create constructor for Proxy that must initialize the method. - CHECK_EQ(GetClassRoot(kJavaLangReflectProxy)->NumDirectMethods(), 16u); + CHECK_EQ(GetClassRoot(kJavaLangReflectProxy)->NumDirectMethods(), 19u); ArtMethod* proxy_constructor = GetClassRoot(kJavaLangReflectProxy)->GetDirectMethodUnchecked( 2, image_pointer_size_); // Ensure constructor is in dex cache so that we can use the dex cache to look up the overridden diff --git a/runtime/class_linker_test.cc b/runtime/class_linker_test.cc index 2c086c59f0..ea2a39c2c0 100644 --- a/runtime/class_linker_test.cc +++ b/runtime/class_linker_test.cc @@ -491,6 +491,7 @@ struct ObjectOffsets : public CheckOffsets<mirror::Object> { struct ClassOffsets : public CheckOffsets<mirror::Class> { ClassOffsets() : CheckOffsets<mirror::Class>(false, "Ljava/lang/Class;") { addOffset(OFFSETOF_MEMBER(mirror::Class, access_flags_), "accessFlags"); + addOffset(OFFSETOF_MEMBER(mirror::Class, annotation_type_), "annotationType"); addOffset(OFFSETOF_MEMBER(mirror::Class, class_flags_), "classFlags"); addOffset(OFFSETOF_MEMBER(mirror::Class, class_loader_), "classLoader"); addOffset(OFFSETOF_MEMBER(mirror::Class, class_size_), "classSize"); @@ -524,15 +525,15 @@ struct ClassOffsets : public CheckOffsets<mirror::Class> { struct StringOffsets : public CheckOffsets<mirror::String> { StringOffsets() : CheckOffsets<mirror::String>(false, "Ljava/lang/String;") { addOffset(OFFSETOF_MEMBER(mirror::String, count_), "count"); - addOffset(OFFSETOF_MEMBER(mirror::String, hash_code_), "hashCode"); + addOffset(OFFSETOF_MEMBER(mirror::String, hash_code_), "hash"); }; }; struct ThrowableOffsets : public CheckOffsets<mirror::Throwable> { ThrowableOffsets() : CheckOffsets<mirror::Throwable>(false, "Ljava/lang/Throwable;") { + addOffset(OFFSETOF_MEMBER(mirror::Throwable, backtrace_), "backtrace"); addOffset(OFFSETOF_MEMBER(mirror::Throwable, cause_), "cause"); addOffset(OFFSETOF_MEMBER(mirror::Throwable, detail_message_), "detailMessage"); - addOffset(OFFSETOF_MEMBER(mirror::Throwable, stack_state_), "stackState"); addOffset(OFFSETOF_MEMBER(mirror::Throwable, stack_trace_), "stackTrace"); addOffset(OFFSETOF_MEMBER(mirror::Throwable, suppressed_exceptions_), "suppressedExceptions"); }; @@ -601,7 +602,7 @@ struct FinalizerReferenceOffsets : public CheckOffsets<mirror::FinalizerReferenc struct AccessibleObjectOffsets : public CheckOffsets<mirror::AccessibleObject> { AccessibleObjectOffsets() : CheckOffsets<mirror::AccessibleObject>( false, "Ljava/lang/reflect/AccessibleObject;") { - addOffset(mirror::AccessibleObject::FlagOffset().Uint32Value(), "flag"); + addOffset(mirror::AccessibleObject::FlagOffset().Uint32Value(), "override"); }; }; diff --git a/runtime/common_runtime_test.cc b/runtime/common_runtime_test.cc index f705a50d55..2f9bbbd76d 100644 --- a/runtime/common_runtime_test.cc +++ b/runtime/common_runtime_test.cc @@ -303,7 +303,12 @@ void CommonRuntimeTest::SetUp() { RuntimeOptions options; - std::string boot_class_path_string = "-Xbootclasspath:" + GetLibCoreDexFileName(); + std::string boot_class_path_string = "-Xbootclasspath"; + for (const std::string &core_dex_file_name : GetLibCoreDexFileNames()) { + boot_class_path_string += ":"; + boot_class_path_string += core_dex_file_name; + } + options.push_back(std::make_pair(boot_class_path_string, nullptr)); options.push_back(std::make_pair("-Xcheck:jni", nullptr)); options.push_back(std::make_pair(min_heap_string, nullptr)); @@ -405,10 +410,30 @@ void CommonRuntimeTest::TearDown() { (*icu_cleanup_fn)(); Runtime::Current()->GetHeap()->VerifyHeap(); // Check for heap corruption after the test + + // Manually closing the JNI libraries. + // Runtime does not support repeatedly doing JNI->CreateVM, thus we need to manually clean up the + // dynamic linking loader so that gtests would not fail. + // Bug: 25785594 + if (runtime_->IsStarted()) { + { + // We retrieve the handle by calling dlopen on the library. To close it, we need to call + // dlclose twice, the first time to undo our dlopen and the second time to actually unload it. + // See man dlopen. + void* handle = dlopen("libjavacore.so", RTLD_LAZY); + dlclose(handle); + CHECK_EQ(0, dlclose(handle)); + } + { + void* handle = dlopen("libopenjdk.so", RTLD_LAZY); + dlclose(handle); + CHECK_EQ(0, dlclose(handle)); + } + } } -std::string CommonRuntimeTest::GetLibCoreDexFileName() { - return GetDexFileName("core-libart"); +std::vector<std::string> CommonRuntimeTest::GetLibCoreDexFileNames() { + return std::vector<std::string>({GetDexFileName("core-oj"), GetDexFileName("core-libart")}); } std::string CommonRuntimeTest::GetDexFileName(const std::string& jar_prefix) { diff --git a/runtime/common_runtime_test.h b/runtime/common_runtime_test.h index 6da2bef214..672bd7173d 100644 --- a/runtime/common_runtime_test.h +++ b/runtime/common_runtime_test.h @@ -77,8 +77,8 @@ class CommonRuntimeTest : public testing::Test { CommonRuntimeTest(); ~CommonRuntimeTest(); - // Gets the path of the libcore dex file. - static std::string GetLibCoreDexFileName(); + // Gets the paths of the libcore dex files. + static std::vector<std::string> GetLibCoreDexFileNames(); // Returns bin directory which contains host's prebuild tools. static std::string GetAndroidHostToolsDir(); diff --git a/runtime/debugger.cc b/runtime/debugger.cc index 62c9d25574..ad52ca516e 100644 --- a/runtime/debugger.cc +++ b/runtime/debugger.cc @@ -2038,29 +2038,28 @@ static void GetChildThreadGroups(ScopedObjectAccessUnchecked& soa, mirror::Objec SHARED_REQUIRES(Locks::mutator_lock_) { CHECK(thread_group != nullptr); - // Get the ArrayList<ThreadGroup> "groups" out of this thread group... - ArtField* groups_field = soa.DecodeField(WellKnownClasses::java_lang_ThreadGroup_groups); - mirror::Object* groups_array_list = groups_field->GetObject(thread_group); - { - // The "groups" field is declared as a java.util.List: check it really is - // an instance of java.util.ArrayList. - CHECK(groups_array_list != nullptr); - mirror::Class* java_util_ArrayList_class = - soa.Decode<mirror::Class*>(WellKnownClasses::java_util_ArrayList); - CHECK(groups_array_list->InstanceOf(java_util_ArrayList_class)); + // Get the int "ngroups" count of this thread group... + ArtField* ngroups_field = soa.DecodeField(WellKnownClasses::java_lang_ThreadGroup_ngroups); + CHECK(ngroups_field != nullptr); + const int32_t size = ngroups_field->GetInt(thread_group); + if (size == 0) { + return; } - // Get the array and size out of the ArrayList<ThreadGroup>... - ArtField* array_field = soa.DecodeField(WellKnownClasses::java_util_ArrayList_array); - ArtField* size_field = soa.DecodeField(WellKnownClasses::java_util_ArrayList_size); - mirror::ObjectArray<mirror::Object>* groups_array = - array_field->GetObject(groups_array_list)->AsObjectArray<mirror::Object>(); - const int32_t size = size_field->GetInt(groups_array_list); + // Get the ThreadGroup[] "groups" out of this thread group... + ArtField* groups_field = soa.DecodeField(WellKnownClasses::java_lang_ThreadGroup_groups); + mirror::Object* groups_array = groups_field->GetObject(thread_group); + + CHECK(groups_array != nullptr); + CHECK(groups_array->IsObjectArray()); + + mirror::ObjectArray<mirror::Object>* groups_array_as_array = + groups_array->AsObjectArray<mirror::Object>(); // Copy the first 'size' elements out of the array into the result. ObjectRegistry* registry = Dbg::GetObjectRegistry(); for (int32_t i = 0; i < size; ++i) { - child_thread_group_ids->push_back(registry->Add(groups_array->Get(i))); + child_thread_group_ids->push_back(registry->Add(groups_array_as_array->Get(i))); } } diff --git a/runtime/dex_file_test.cc b/runtime/dex_file_test.cc index 0a167bb8f7..796701d86b 100644 --- a/runtime/dex_file_test.cc +++ b/runtime/dex_file_test.cc @@ -206,7 +206,7 @@ TEST_F(DexFileTest, GetChecksum) { uint32_t checksum; ScopedObjectAccess soa(Thread::Current()); std::string error_msg; - EXPECT_TRUE(DexFile::GetChecksum(GetLibCoreDexFileName().c_str(), &checksum, &error_msg)) + EXPECT_TRUE(DexFile::GetChecksum(GetLibCoreDexFileNames()[0].c_str(), &checksum, &error_msg)) << error_msg; EXPECT_EQ(java_lang_dex_file_->GetLocationChecksum(), checksum); } diff --git a/runtime/jni_internal_test.cc b/runtime/jni_internal_test.cc index b41d16b299..c718466eae 100644 --- a/runtime/jni_internal_test.cc +++ b/runtime/jni_internal_test.cc @@ -2091,8 +2091,7 @@ TEST_F(JniInternalTest, NewDirectBuffer_GetDirectBufferAddress_GetDirectBufferCa MakeExecutable(nullptr, "java.lang.Class"); MakeExecutable(nullptr, "java.lang.Object"); MakeExecutable(nullptr, "java.nio.DirectByteBuffer"); - MakeExecutable(nullptr, "java.nio.MemoryBlock"); - MakeExecutable(nullptr, "java.nio.MemoryBlock$UnmanagedBlock"); + MakeExecutable(nullptr, "java.nio.Bits"); MakeExecutable(nullptr, "java.nio.MappedByteBuffer"); MakeExecutable(nullptr, "java.nio.ByteBuffer"); MakeExecutable(nullptr, "java.nio.Buffer"); diff --git a/runtime/mirror/class.h b/runtime/mirror/class.h index 0ab5b97d72..98e1440046 100644 --- a/runtime/mirror/class.h +++ b/runtime/mirror/class.h @@ -559,8 +559,8 @@ class MANAGED Class FINAL : public Object { // The size of java.lang.Class.class. static uint32_t ClassClassSize(size_t pointer_size) { // The number of vtable entries in java.lang.Class. - uint32_t vtable_entries = Object::kVTableLength + 65; - return ComputeClassSize(true, vtable_entries, 0, 0, 0, 1, 0, pointer_size); + uint32_t vtable_entries = Object::kVTableLength + 69; + return ComputeClassSize(true, vtable_entries, 0, 0, 4, 1, 0, pointer_size); } // The size of a java.lang.Class representing a primitive such as int.class. @@ -1206,6 +1206,8 @@ class MANAGED Class FINAL : public Object { void VisitReferences(mirror::Class* klass, const Visitor& visitor) SHARED_REQUIRES(Locks::mutator_lock_); + HeapReference<Object> annotation_type_; + // Defining class loader, or null for the "bootstrap" system loader. HeapReference<ClassLoader> class_loader_; @@ -1251,6 +1253,9 @@ class MANAGED Class FINAL : public Object { // virtual_ methods_ for miranda methods. HeapReference<PointerArray> vtable_; + // Access flags; low 16 bits are defined by VM spec. + uint32_t access_flags_; + // Short cuts to dex_cache_ member for fast compiled code access. uint64_t dex_cache_strings_; @@ -1275,9 +1280,6 @@ class MANAGED Class FINAL : public Object { // length-prefixed array. uint64_t virtual_methods_; - // Access flags; low 16 bits are defined by VM spec. - uint32_t access_flags_; - // Class flags to help speed up visiting object references. uint32_t class_flags_; diff --git a/runtime/mirror/reference-inl.h b/runtime/mirror/reference-inl.h index 01e99b9e9d..bd4a9c1031 100644 --- a/runtime/mirror/reference-inl.h +++ b/runtime/mirror/reference-inl.h @@ -23,7 +23,7 @@ namespace art { namespace mirror { inline uint32_t Reference::ClassSize(size_t pointer_size) { - uint32_t vtable_entries = Object::kVTableLength + 5; + uint32_t vtable_entries = Object::kVTableLength + 4; return Class::ComputeClassSize(false, vtable_entries, 2, 0, 0, 0, 0, pointer_size); } diff --git a/runtime/mirror/string-inl.h b/runtime/mirror/string-inl.h index 28a830d86b..cdf468c809 100644 --- a/runtime/mirror/string-inl.h +++ b/runtime/mirror/string-inl.h @@ -33,8 +33,8 @@ namespace art { namespace mirror { inline uint32_t String::ClassSize(size_t pointer_size) { - uint32_t vtable_entries = Object::kVTableLength + 52; - return Class::ComputeClassSize(true, vtable_entries, 0, 1, 0, 1, 2, pointer_size); + uint32_t vtable_entries = Object::kVTableLength + 53; + return Class::ComputeClassSize(true, vtable_entries, 0, 2, 0, 1, 2, pointer_size); } // Sets string count in the allocation code path to ensure it is guarded by a CAS. diff --git a/runtime/mirror/throwable.cc b/runtime/mirror/throwable.cc index e215994fb7..f068b3e8b8 100644 --- a/runtime/mirror/throwable.cc +++ b/runtime/mirror/throwable.cc @@ -56,9 +56,9 @@ void Throwable::SetCause(Throwable* cause) { void Throwable::SetStackState(Object* state) SHARED_REQUIRES(Locks::mutator_lock_) { CHECK(state != nullptr); if (Runtime::Current()->IsActiveTransaction()) { - SetFieldObjectVolatile<true>(OFFSET_OF_OBJECT_MEMBER(Throwable, stack_state_), state); + SetFieldObjectVolatile<true>(OFFSET_OF_OBJECT_MEMBER(Throwable, backtrace_), state); } else { - SetFieldObjectVolatile<false>(OFFSET_OF_OBJECT_MEMBER(Throwable, stack_state_), state); + SetFieldObjectVolatile<false>(OFFSET_OF_OBJECT_MEMBER(Throwable, backtrace_), state); } } diff --git a/runtime/mirror/throwable.h b/runtime/mirror/throwable.h index 0f488dc46a..6aacc8dc4e 100644 --- a/runtime/mirror/throwable.h +++ b/runtime/mirror/throwable.h @@ -60,16 +60,16 @@ class MANAGED Throwable : public Object { private: Object* GetStackState() SHARED_REQUIRES(Locks::mutator_lock_) { - return GetFieldObjectVolatile<Object>(OFFSET_OF_OBJECT_MEMBER(Throwable, stack_state_)); + return GetFieldObjectVolatile<Object>(OFFSET_OF_OBJECT_MEMBER(Throwable, backtrace_)); } Object* GetStackTrace() SHARED_REQUIRES(Locks::mutator_lock_) { - return GetFieldObjectVolatile<Object>(OFFSET_OF_OBJECT_MEMBER(Throwable, stack_trace_)); + return GetFieldObjectVolatile<Object>(OFFSET_OF_OBJECT_MEMBER(Throwable, backtrace_)); } // Field order required by test "ValidateFieldOrderOfJavaCppUnionClasses". + HeapReference<Object> backtrace_; // Note this is Java volatile: HeapReference<Throwable> cause_; HeapReference<String> detail_message_; - HeapReference<Object> stack_state_; // Note this is Java volatile: HeapReference<Object> stack_trace_; HeapReference<Object> suppressed_exceptions_; diff --git a/runtime/native/OpenjdkJvm.cc b/runtime/native/OpenjdkJvm.cc new file mode 100644 index 0000000000..15cec90a70 --- /dev/null +++ b/runtime/native/OpenjdkJvm.cc @@ -0,0 +1,519 @@ +/* + * Copyright (C) 2014 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. + */ + +/* + * Services that OpenJDK expects the VM to provide. + */ +#include<stdio.h> +#include <dlfcn.h> +#include <limits.h> +#include <unistd.h> + +#include "common_throws.h" +#include "gc/heap.h" +#include "thread.h" +#include "thread_list.h" +#include "runtime.h" +#include "handle_scope-inl.h" +#include "scoped_thread_state_change.h" +#include "ScopedUtfChars.h" +#include "mirror/class_loader.h" +#include "verify_object-inl.h" +#include "base/logging.h" +#include "base/macros.h" +#include "../../libcore/ojluni/src/main/native/jvm.h" // TODO(narayan): fix it +#include "jni_internal.h" +#include "mirror/string-inl.h" +#include "scoped_fast_native_object_access.h" +#include "ScopedLocalRef.h" +#include <sys/time.h> +#include <sys/socket.h> +#include <sys/ioctl.h> + +#ifdef __ANDROID__ +// This function is provided by android linker. +extern "C" void android_update_LD_LIBRARY_PATH(const char* ld_library_path); +#endif // __ANDROID__ + +#undef LOG_TAG +#define LOG_TAG "artopenjdx" + +using art::DEBUG; +using art::WARNING; +using art::VERBOSE; +using art::INFO; +using art::ERROR; +using art::FATAL; + +/* posix open() with extensions; used by e.g. ZipFile */ +JNIEXPORT jint JVM_Open(const char* fname, jint flags, jint mode) { + LOG(DEBUG) << "JVM_Open fname='" << fname << "', flags=" << flags << ", mode=" << mode; + + /* + * The call is expected to handle JVM_O_DELETE, which causes the file + * to be removed after it is opened. Also, some code seems to + * want the special return value JVM_EEXIST if the file open fails + * due to O_EXCL. + */ + int fd = TEMP_FAILURE_RETRY(open(fname, flags & ~JVM_O_DELETE, mode)); + if (fd < 0) { + int err = errno; + LOG(DEBUG) << "open(" << fname << ") failed: " << strerror(errno); + if (err == EEXIST) { + return JVM_EEXIST; + } else { + return -1; + } + } + + if (flags & JVM_O_DELETE) { + LOG(DEBUG) << "Deleting '" << fname << "' after open\n"; + if (unlink(fname) != 0) { + LOG(WARNING) << "Post-open deletion of '" << fname << "' failed: " << strerror(errno); + } + /* ignore */ + } + + LOG(VERBOSE) << "open(" << fname << ") --> " << fd; + return fd; +} + +/* posix close() */ +JNIEXPORT jint JVM_Close(jint fd) { + LOG(DEBUG) << "JVM_Close fd=" << fd; + // don't want TEMP_FAILURE_RETRY here -- file is closed even if EINTR + return close(fd); +} + +/* posix read() */ +JNIEXPORT jint JVM_Read(jint fd, char* buf, jint nbytes) { + LOG(DEBUG) << "JVM_Read fd=" << fd << ", buf='" << buf << "', nbytes=" << nbytes; + return TEMP_FAILURE_RETRY(read(fd, buf, nbytes)); +} + +/* posix write(); is used to write messages to stderr */ +JNIEXPORT jint JVM_Write(jint fd, char* buf, jint nbytes) { + LOG(DEBUG) << "JVM_Write fd=" << fd << ", buf='" << buf << "', nbytes=" << nbytes; + return TEMP_FAILURE_RETRY(write(fd, buf, nbytes)); +} + +/* posix lseek() */ +JNIEXPORT jlong JVM_Lseek(jint fd, jlong offset, jint whence) { + LOG(DEBUG) << "JVM_Lseek fd=" << fd << ", offset=" << offset << ", whence=" << whence; + return TEMP_FAILURE_RETRY(lseek(fd, offset, whence)); +} + +/* + * "raw monitors" seem to be expected to behave like non-recursive pthread + * mutexes. They're used by ZipFile. + */ +JNIEXPORT void* JVM_RawMonitorCreate(void) { + LOG(DEBUG) << "JVM_RawMonitorCreate"; + pthread_mutex_t* newMutex = + reinterpret_cast<pthread_mutex_t*>(malloc(sizeof(pthread_mutex_t))); + pthread_mutex_init(newMutex, NULL); + return newMutex; +} + +JNIEXPORT void JVM_RawMonitorDestroy(void* mon) { + LOG(DEBUG) << "JVM_RawMonitorDestroy mon=" << mon; + pthread_mutex_destroy(reinterpret_cast<pthread_mutex_t*>(mon)); +} + +JNIEXPORT jint JVM_RawMonitorEnter(void* mon) { + LOG(DEBUG) << "JVM_RawMonitorEnter mon=" << mon; + return pthread_mutex_lock(reinterpret_cast<pthread_mutex_t*>(mon)); +} + +JNIEXPORT void JVM_RawMonitorExit(void* mon) { + LOG(DEBUG) << "JVM_RawMonitorExit mon=" << mon; + pthread_mutex_unlock(reinterpret_cast<pthread_mutex_t*>(mon)); +} + +JNIEXPORT char* JVM_NativePath(char* path) { + LOG(DEBUG) << "JVM_NativePath path='" << path << "'"; + return path; +} + +JNIEXPORT jint JVM_GetLastErrorString(char* buf, int len) { +#if defined(__GLIBC__) || defined(__BIONIC__) + int err = errno; // grab before JVM_TRACE can trash it + LOG(DEBUG) << "JVM_GetLastErrorString buf=" << buf << ", len=" << len; + + if (len == 0) { + return 0; + } + + char* result = strerror_r(err, buf, len); + if (result != buf) { + strncpy(buf, result, len); + buf[len - 1] = '\0'; + } + + return strlen(buf); +#else + UNUSED(buf); + UNUSED(len); + return -1; +#endif +} + +JNIEXPORT int jio_fprintf(FILE* fp, const char* fmt, ...) { + va_list args; + + va_start(args, fmt); + int len = jio_vfprintf(fp, fmt, args); + va_end(args); + + return len; +} + +JNIEXPORT int jio_vfprintf(FILE* fp, const char* fmt, va_list args) { + assert(fp != NULL); + return vfprintf(fp, fmt, args); +} + +/* posix fsync() */ +JNIEXPORT jint JVM_Sync(jint fd) { + LOG(DEBUG) << "JVM_Sync fd=" << fd; + return TEMP_FAILURE_RETRY(fsync(fd)); +} + +JNIEXPORT void* JVM_FindLibraryEntry(void* handle, const char* name) { + LOG(DEBUG) << "JVM_FindLibraryEntry handle=" << handle << " name=" << name; + return dlsym(handle, name); +} + +JNIEXPORT jlong JVM_CurrentTimeMillis(JNIEnv* env, jclass clazz ATTRIBUTE_UNUSED) { + LOG(DEBUG) << "JVM_CurrentTimeMillis env=" << env; + struct timeval tv; + + gettimeofday(&tv, (struct timezone *) NULL); + jlong when = tv.tv_sec * 1000LL + tv.tv_usec / 1000; + return when; +} + +JNIEXPORT jint JVM_Socket(jint domain, jint type, jint protocol) { + LOG(DEBUG) << "JVM_Socket domain=" << domain << ", type=" << type << ", protocol=" << protocol; + + return TEMP_FAILURE_RETRY(socket(domain, type, protocol)); +} + +JNIEXPORT jint JVM_InitializeSocketLibrary() { + return 0; +} + +int jio_vsnprintf(char *str, size_t count, const char *fmt, va_list args) { + if ((intptr_t)count <= 0) return -1; + return vsnprintf(str, count, fmt, args); +} + +int jio_snprintf(char *str, size_t count, const char *fmt, ...) { + va_list args; + int len; + va_start(args, fmt); + len = jio_vsnprintf(str, count, fmt, args); + va_end(args); + return len; +} + +JNIEXPORT jint JVM_SetSockOpt(jint fd, int level, int optname, + const char* optval, int optlen) { + LOG(DEBUG) << "JVM_SetSockOpt fd=" << fd << ", level=" << level << ", optname=" << optname + << ", optval=" << optval << ", optlen=" << optlen; + return TEMP_FAILURE_RETRY(setsockopt(fd, level, optname, optval, optlen)); +} + +JNIEXPORT jint JVM_SocketShutdown(jint fd, jint howto) { + LOG(DEBUG) << "JVM_SocketShutdown fd=" << fd << ", howto=" << howto; + return TEMP_FAILURE_RETRY(shutdown(fd, howto)); +} + +JNIEXPORT jint JVM_GetSockOpt(jint fd, int level, int optname, char* optval, + int* optlen) { + LOG(DEBUG) << "JVM_GetSockOpt fd=" << fd << ", level=" << level << ", optname=" << optname + << ", optval=" << optval << ", optlen=" << optlen; + + socklen_t len = *optlen; + int cc = TEMP_FAILURE_RETRY(getsockopt(fd, level, optname, optval, &len)); + *optlen = len; + return cc; +} + +JNIEXPORT jint JVM_GetSockName(jint fd, struct sockaddr* addr, int* addrlen) { + LOG(DEBUG) << "JVM_GetSockName fd=" << fd << ", addr=" << addr << ", addrlen=" << addrlen; + + socklen_t len = *addrlen; + int cc = TEMP_FAILURE_RETRY(getsockname(fd, addr, &len)); + *addrlen = len; + return cc; +} + +JNIEXPORT jint JVM_SocketAvailable(jint fd, jint* result) { + LOG(DEBUG) << "JVM_SocketAvailable fd=" << fd << ", result=" << result; + + if (TEMP_FAILURE_RETRY(ioctl(fd, FIONREAD, result)) < 0) { + LOG(DEBUG) << "ioctl(" << fd << ", FIONREAD) failed: " << strerror(errno); + return JNI_FALSE; + } + + return JNI_TRUE; +} + +JNIEXPORT jint JVM_Send(jint fd, char* buf, jint nBytes, jint flags) { + LOG(DEBUG) << "JVM_Send fd=" << fd << ", buf=" << buf << ", nBytes=" + << nBytes << ", flags=" << flags; + + return TEMP_FAILURE_RETRY(send(fd, buf, nBytes, flags)); +} + +JNIEXPORT jint JVM_SocketClose(jint fd) { + LOG(DEBUG) << "JVM_SocketClose fd=" << fd; + + // don't want TEMP_FAILURE_RETRY here -- file is closed even if EINTR + return close(fd); +} + +JNIEXPORT jint JVM_Listen(jint fd, jint count) { + LOG(DEBUG) << "JVM_Listen fd=" << fd << ", count=" << count; + + return TEMP_FAILURE_RETRY(listen(fd, count)); +} + +JNIEXPORT jint JVM_Connect(jint fd, struct sockaddr* addr, jint addrlen) { + LOG(DEBUG) << "JVM_Connect fd=" << fd << ", addr=" << addr << ", addrlen=" << addrlen; + + return TEMP_FAILURE_RETRY(connect(fd, addr, addrlen)); +} + +JNIEXPORT int JVM_GetHostName(char* name, int namelen) { + LOG(DEBUG) << "JVM_GetHostName name=" << name << ", namelen=" << namelen; + + return TEMP_FAILURE_RETRY(gethostname(name, namelen)); +} + +JNIEXPORT jstring JVM_InternString(JNIEnv* env, jstring jstr) { + LOG(DEBUG) << "JVM_InternString env=" << env << ", jstr=" << jstr; + art::ScopedFastNativeObjectAccess soa(env); + art::mirror::String* s = soa.Decode<art::mirror::String*>(jstr); + art::mirror::String* result = s->Intern(); + return soa.AddLocalReference<jstring>(result); +} + +JNIEXPORT jlong JVM_FreeMemory(void) { + return art::Runtime::Current()->GetHeap()->GetFreeMemory(); +} + +JNIEXPORT jlong JVM_TotalMemory(void) { + return art::Runtime::Current()->GetHeap()->GetTotalMemory(); +} + +JNIEXPORT jlong JVM_MaxMemory(void) { + return art::Runtime::Current()->GetHeap()->GetMaxMemory(); +} + +JNIEXPORT void JVM_GC(void) { + if (art::Runtime::Current()->IsExplicitGcDisabled()) { + LOG(INFO) << "Explicit GC skipped."; + return; + } + art::Runtime::Current()->GetHeap()->CollectGarbage(false); +} + +JNIEXPORT __attribute__((noreturn)) void JVM_Exit(jint status) { + LOG(INFO) << "System.exit called, status: " << status; + art::Runtime::Current()->CallExitHook(status); + exit(status); +} + +static void SetLdLibraryPath(JNIEnv* env, jstring javaLdLibraryPath) { +#ifdef __ANDROID__ + if (javaLdLibraryPath != nullptr) { + ScopedUtfChars ldLibraryPath(env, javaLdLibraryPath); + if (ldLibraryPath.c_str() != nullptr) { + android_update_LD_LIBRARY_PATH(ldLibraryPath.c_str()); + } + } + +#else + LOG(WARNING) << "android_update_LD_LIBRARY_PATH not found; .so dependencies will not work!"; + UNUSED(javaLdLibraryPath, env); +#endif +} + + +JNIEXPORT jstring JVM_NativeLoad(JNIEnv* env, jstring javaFilename, jobject javaLoader, + jstring javaLdLibraryPath, jstring javaLibraryPermittedPath) { + ScopedUtfChars filename(env, javaFilename); + if (filename.c_str() == NULL) { + return NULL; + } + + int32_t target_sdk_version = art::Runtime::Current()->GetTargetSdkVersion(); + + // Starting with N nativeLoad uses classloader local + // linker namespace instead of global LD_LIBRARY_PATH + // (23 is Marshmallow) + if (target_sdk_version <= 23) { + SetLdLibraryPath(env, javaLdLibraryPath); + } + + std::string error_msg; + { + art::ScopedObjectAccess soa(env); + art::StackHandleScope<1> hs(soa.Self()); + art::JavaVMExt* vm = art::Runtime::Current()->GetJavaVM(); + bool success = vm->LoadNativeLibrary(env, filename.c_str(), javaLoader, + javaLdLibraryPath, javaLibraryPermittedPath, &error_msg); + if (success) { + return nullptr; + } + } + + // Don't let a pending exception from JNI_OnLoad cause a CheckJNI issue with NewStringUTF. + env->ExceptionClear(); + return env->NewStringUTF(error_msg.c_str()); +} + +JNIEXPORT void JVM_StartThread(JNIEnv* env, jobject jthread, jlong stack_size, jboolean daemon) { + art::Thread::CreateNativeThread(env, jthread, stack_size, daemon == JNI_TRUE); +} + +JNIEXPORT void JVM_SetThreadPriority(JNIEnv* env, jobject jthread, jint prio) { + art::ScopedObjectAccess soa(env); + art::MutexLock mu(soa.Self(), *art::Locks::thread_list_lock_); + art::Thread* thread = art::Thread::FromManagedThread(soa, jthread); + if (thread != NULL) { + thread->SetNativePriority(prio); + } +} + +JNIEXPORT void JVM_Yield(JNIEnv* env ATTRIBUTE_UNUSED, jclass threadClass ATTRIBUTE_UNUSED) { + sched_yield(); +} + +JNIEXPORT void JVM_Sleep(JNIEnv* env, jclass threadClass ATTRIBUTE_UNUSED, + jobject java_lock, jlong millis) { + art::ScopedFastNativeObjectAccess soa(env); + art::mirror::Object* lock = soa.Decode<art::mirror::Object*>(java_lock); + art::Monitor::Wait(art::Thread::Current(), lock, millis, 0, true, art::kSleeping); +} + +JNIEXPORT jobject JVM_CurrentThread(JNIEnv* env, jclass unused ATTRIBUTE_UNUSED) { + art::ScopedFastNativeObjectAccess soa(env); + return soa.AddLocalReference<jobject>(soa.Self()->GetPeer()); +} + +JNIEXPORT void JVM_Interrupt(JNIEnv* env, jobject jthread) { + art::ScopedFastNativeObjectAccess soa(env); + art::MutexLock mu(soa.Self(), *art::Locks::thread_list_lock_); + art::Thread* thread = art::Thread::FromManagedThread(soa, jthread); + if (thread != nullptr) { + thread->Interrupt(soa.Self()); + } +} + +JNIEXPORT jboolean JVM_IsInterrupted(JNIEnv* env, jobject jthread, jboolean clearInterrupted) { + if (clearInterrupted) { + return static_cast<art::JNIEnvExt*>(env)->self->Interrupted() ? JNI_TRUE : JNI_FALSE; + } else { + art::ScopedFastNativeObjectAccess soa(env); + art::MutexLock mu(soa.Self(), *art::Locks::thread_list_lock_); + art::Thread* thread = art::Thread::FromManagedThread(soa, jthread); + return (thread != nullptr) ? thread->IsInterrupted() : JNI_FALSE; + } +} + +JNIEXPORT jboolean JVM_HoldsLock(JNIEnv* env, jclass unused ATTRIBUTE_UNUSED, jobject jobj) { + art::ScopedObjectAccess soa(env); + art::mirror::Object* object = soa.Decode<art::mirror::Object*>(jobj); + if (object == NULL) { + art::ThrowNullPointerException("object == null"); + return JNI_FALSE; + } + return soa.Self()->HoldsLock(object); +} + +JNIEXPORT void JVM_SetNativeThreadName(JNIEnv* env, jobject jthread, jstring java_name) { + ScopedUtfChars name(env, java_name); + { + art::ScopedObjectAccess soa(env); + if (soa.Decode<art::mirror::Object*>(jthread) == soa.Self()->GetPeer()) { + soa.Self()->SetThreadName(name.c_str()); + return; + } + } + // Suspend thread to avoid it from killing itself while we set its name. We don't just hold the + // thread list lock to avoid this, as setting the thread name causes mutator to lock/unlock + // in the DDMS send code. + art::ThreadList* thread_list = art::Runtime::Current()->GetThreadList(); + bool timed_out; + // Take suspend thread lock to avoid races with threads trying to suspend this one. + art::Thread* thread; + { + thread = thread_list->SuspendThreadByPeer(jthread, true, false, &timed_out); + } + if (thread != NULL) { + { + art::ScopedObjectAccess soa(env); + thread->SetThreadName(name.c_str()); + } + thread_list->Resume(thread, false); + } else if (timed_out) { + LOG(ERROR) << "Trying to set thread name to '" << name.c_str() << "' failed as the thread " + "failed to suspend within a generous timeout."; + } +} + +JNIEXPORT jint JVM_IHashCode(JNIEnv* env ATTRIBUTE_UNUSED, + jobject javaObject ATTRIBUTE_UNUSED) { + UNIMPLEMENTED(FATAL) << "JVM_IHashCode is not implemented"; + return 0; +} + +JNIEXPORT jlong JVM_NanoTime(JNIEnv* env ATTRIBUTE_UNUSED, jclass unused ATTRIBUTE_UNUSED) { + UNIMPLEMENTED(FATAL) << "JVM_NanoTime is not implemented"; + return 0L; +} + +JNIEXPORT void JVM_ArrayCopy(JNIEnv* /* env */, jclass /* unused */, jobject /* javaSrc */, + jint /* srcPos */, jobject /* javaDst */, jint /* dstPos */, + jint /* length */) { + UNIMPLEMENTED(FATAL) << "JVM_ArrayCopy is not implemented"; +} + +JNIEXPORT jint JVM_FindSignal(const char* name ATTRIBUTE_UNUSED) { + LOG(FATAL) << "JVM_FindSignal is not implemented"; + return 0; +} + +JNIEXPORT void* JVM_RegisterSignal(jint signum ATTRIBUTE_UNUSED, void* handler ATTRIBUTE_UNUSED) { + LOG(FATAL) << "JVM_RegisterSignal is not implemented"; + return nullptr; +} + +JNIEXPORT jboolean JVM_RaiseSignal(jint signum ATTRIBUTE_UNUSED) { + LOG(FATAL) << "JVM_RaiseSignal is not implemented"; + return JNI_FALSE; +} + +JNIEXPORT __attribute__((noreturn)) void JVM_Halt(jint code) { + exit(code); +} + +JNIEXPORT jboolean JVM_IsNaN(jdouble d) { + return isnan(d); +} diff --git a/runtime/native/dalvik_system_ZygoteHooks.cc b/runtime/native/dalvik_system_ZygoteHooks.cc index ae1a4d7823..67d825efaa 100644 --- a/runtime/native/dalvik_system_ZygoteHooks.cc +++ b/runtime/native/dalvik_system_ZygoteHooks.cc @@ -129,7 +129,11 @@ static jlong ZygoteHooks_nativePreFork(JNIEnv* env, jclass) { return reinterpret_cast<jlong>(ThreadForEnv(env)); } -static void ZygoteHooks_nativePostForkChild(JNIEnv* env, jclass, jlong token, jint debug_flags, +static void ZygoteHooks_nativePostForkChild(JNIEnv* env, + jclass, + jlong token, + jint debug_flags, + jboolean is_system_server, jstring instruction_set) { Thread* thread = reinterpret_cast<Thread*>(token); // Our system thread ID, etc, has changed so reset Thread state. @@ -174,22 +178,24 @@ static void ZygoteHooks_nativePostForkChild(JNIEnv* env, jclass, jlong token, ji } } - if (instruction_set != nullptr) { + if (instruction_set != nullptr && !is_system_server) { ScopedUtfChars isa_string(env, instruction_set); InstructionSet isa = GetInstructionSetFromString(isa_string.c_str()); Runtime::NativeBridgeAction action = Runtime::NativeBridgeAction::kUnload; if (isa != kNone && isa != kRuntimeISA) { action = Runtime::NativeBridgeAction::kInitialize; } - Runtime::Current()->InitNonZygoteOrPostFork(env, action, isa_string.c_str()); + Runtime::Current()->InitNonZygoteOrPostFork( + env, is_system_server, action, isa_string.c_str()); } else { - Runtime::Current()->InitNonZygoteOrPostFork(env, Runtime::NativeBridgeAction::kUnload, nullptr); + Runtime::Current()->InitNonZygoteOrPostFork( + env, is_system_server, Runtime::NativeBridgeAction::kUnload, nullptr); } } static JNINativeMethod gMethods[] = { NATIVE_METHOD(ZygoteHooks, nativePreFork, "()J"), - NATIVE_METHOD(ZygoteHooks, nativePostForkChild, "(JILjava/lang/String;)V"), + NATIVE_METHOD(ZygoteHooks, nativePostForkChild, "(JIZLjava/lang/String;)V"), }; void register_dalvik_system_ZygoteHooks(JNIEnv* env) { diff --git a/runtime/native/java_lang_reflect_Constructor.cc b/runtime/native/java_lang_reflect_Constructor.cc index 45b948408e..ddcaadefa3 100644 --- a/runtime/native/java_lang_reflect_Constructor.cc +++ b/runtime/native/java_lang_reflect_Constructor.cc @@ -86,7 +86,7 @@ static jboolean Constructor_isAnnotationPresentNative(JNIEnv* env, jobject javaM * with an interface, array, or primitive class. If this is coming from * native, it is OK to avoid access checks since JNI does not enforce them. */ -static jobject Constructor_newInstance(JNIEnv* env, jobject javaMethod, jobjectArray javaArgs) { +static jobject Constructor_newInstance0(JNIEnv* env, jobject javaMethod, jobjectArray javaArgs) { ScopedFastNativeObjectAccess soa(env); mirror::Constructor* m = soa.Decode<mirror::Constructor*>(javaMethod); StackHandleScope<1> hs(soa.Self()); @@ -99,7 +99,9 @@ static jobject Constructor_newInstance(JNIEnv* env, jobject javaMethod, jobjectA } // Verify that we can access the class. if (!m->IsAccessible() && !c->IsPublic()) { - auto* caller = GetCallingClass(soa.Self(), 1); + // Go 2 frames back, this method is always called from newInstance0, which is called from + // Constructor.newInstance(Object... args). + auto* caller = GetCallingClass(soa.Self(), 2); // If caller is null, then we called from JNI, just avoid the check since JNI avoids most // access checks anyways. TODO: Investigate if this the correct behavior. if (caller != nullptr && !caller->CanAccess(c.Get())) { @@ -127,7 +129,7 @@ static jobject Constructor_newInstance(JNIEnv* env, jobject javaMethod, jobjectA // String constructor is replaced by a StringFactory method in InvokeMethod. if (c->IsStringClass()) { - return InvokeMethod(soa, javaMethod, nullptr, javaArgs, 1); + return InvokeMethod(soa, javaMethod, nullptr, javaArgs, 2); } mirror::Object* receiver = @@ -136,11 +138,18 @@ static jobject Constructor_newInstance(JNIEnv* env, jobject javaMethod, jobjectA return nullptr; } jobject javaReceiver = soa.AddLocalReference<jobject>(receiver); - InvokeMethod(soa, javaMethod, javaReceiver, javaArgs, 1); + InvokeMethod(soa, javaMethod, javaReceiver, javaArgs, 2); // Constructors are ()V methods, so we shouldn't touch the result of InvokeMethod. return javaReceiver; } +static jobject Constructor_newInstanceFromSerialization(JNIEnv* env, jclass unused ATTRIBUTE_UNUSED, + jclass ctorClass, jclass allocClass) { + jmethodID ctor = env->GetMethodID(ctorClass, "<init>", "()V"); + DCHECK(ctor != NULL); + return env->NewObject(allocClass, ctor); +} + static JNINativeMethod gMethods[] = { NATIVE_METHOD(Constructor, getAnnotationNative, "!(Ljava/lang/Class;)Ljava/lang/annotation/Annotation;"), @@ -149,7 +158,8 @@ static JNINativeMethod gMethods[] = { NATIVE_METHOD(Constructor, getParameterAnnotationsNative, "!()[[Ljava/lang/annotation/Annotation;"), NATIVE_METHOD(Constructor, isAnnotationPresentNative, "!(Ljava/lang/Class;)Z"), - NATIVE_METHOD(Constructor, newInstance, "!([Ljava/lang/Object;)Ljava/lang/Object;"), + NATIVE_METHOD(Constructor, newInstance0, "!([Ljava/lang/Object;)Ljava/lang/Object;"), + NATIVE_METHOD(Constructor, newInstanceFromSerialization, "!(Ljava/lang/Class;Ljava/lang/Class;)Ljava/lang/Object;"), }; void register_java_lang_reflect_Constructor(JNIEnv* env) { diff --git a/runtime/native/sun_misc_Unsafe.cc b/runtime/native/sun_misc_Unsafe.cc index 770644cef0..82be34e154 100644 --- a/runtime/native/sun_misc_Unsafe.cc +++ b/runtime/native/sun_misc_Unsafe.cc @@ -15,7 +15,7 @@ */ #include "sun_misc_Unsafe.h" - +#include "common_throws.h" #include "gc/accounting/card_table-inl.h" #include "jni_internal.h" #include "mirror/array.h" @@ -23,6 +23,10 @@ #include "mirror/object-inl.h" #include "scoped_fast_native_object_access.h" +#include <unistd.h> +#include <stdlib.h> +#include <string.h> + namespace art { static jboolean Unsafe_compareAndSwapInt(JNIEnv* env, jobject, jobject javaObj, jlong offset, @@ -185,6 +189,279 @@ static jint Unsafe_getArrayIndexScaleForComponentType(JNIEnv* env, jclass, jobje return Primitive::ComponentSize(primitive_type); } +static jint Unsafe_addressSize(JNIEnv* env ATTRIBUTE_UNUSED, jobject ob ATTRIBUTE_UNUSED) { + return sizeof(void*); +} + +static jint Unsafe_pageSize(JNIEnv* env ATTRIBUTE_UNUSED, jobject ob ATTRIBUTE_UNUSED) { + return sysconf(_SC_PAGESIZE); +} + +static jlong Unsafe_allocateMemory(JNIEnv* env, jobject, jlong bytes) { + ScopedFastNativeObjectAccess soa(env); + // bytes is nonnegative and fits into size_t + if (bytes < 0 || bytes != (jlong)(size_t) bytes) { + ThrowIllegalAccessException("wrong number of bytes"); + return 0; + } + void* mem = malloc(bytes); + if (mem == nullptr) { + soa.Self()->ThrowOutOfMemoryError("native alloc"); + return 0; + } + return (uintptr_t) mem; +} + +static void Unsafe_freeMemory(JNIEnv* env ATTRIBUTE_UNUSED, jobject, jlong address) { + free(reinterpret_cast<void*>(static_cast<uintptr_t>(address))); +} + +static void Unsafe_setMemory(JNIEnv* env ATTRIBUTE_UNUSED, jobject, jlong address, jlong bytes, jbyte value) { + memset(reinterpret_cast<void*>(static_cast<uintptr_t>(address)), value, bytes); +} + +static jbyte Unsafe_getByte$(JNIEnv* env ATTRIBUTE_UNUSED, jobject, jlong address) { + return *reinterpret_cast<jbyte*>(address); +} + +static void Unsafe_putByte$(JNIEnv* env ATTRIBUTE_UNUSED, jobject, jlong address, jbyte value) { + *reinterpret_cast<jbyte*>(address) = value; +} + +static jshort Unsafe_getShort$(JNIEnv* env ATTRIBUTE_UNUSED, jobject, jlong address) { + return *reinterpret_cast<jshort*>(address); +} + +static void Unsafe_putShort$(JNIEnv* env ATTRIBUTE_UNUSED, jobject, jlong address, jshort value) { + *reinterpret_cast<jshort*>(address) = value; +} + +static jchar Unsafe_getChar$(JNIEnv* env ATTRIBUTE_UNUSED, jobject, jlong address) { + return *reinterpret_cast<jchar*>(address); +} + +static void Unsafe_putChar$(JNIEnv* env ATTRIBUTE_UNUSED, jobject, jlong address, jchar value) { + *reinterpret_cast<jchar*>(address) = value; +} + +static jint Unsafe_getInt$(JNIEnv* env ATTRIBUTE_UNUSED, jobject, jlong address) { + return *reinterpret_cast<jint*>(address); +} + +static void Unsafe_putInt$(JNIEnv* env ATTRIBUTE_UNUSED, jobject, jlong address, jint value) { + *reinterpret_cast<jint*>(address) = value; +} + +static jlong Unsafe_getLong$(JNIEnv* env ATTRIBUTE_UNUSED, jobject, jlong address) { + return *reinterpret_cast<jlong*>(address); +} + +static void Unsafe_putLong$(JNIEnv* env ATTRIBUTE_UNUSED, jobject, jlong address, jlong value) { + *reinterpret_cast<jlong*>(address) = value; +} + +static jfloat Unsafe_getFloat$(JNIEnv* env ATTRIBUTE_UNUSED, jobject, jlong address) { + return *reinterpret_cast<jfloat*>(address); +} + +static void Unsafe_putFloat$(JNIEnv* env ATTRIBUTE_UNUSED, jobject, jlong address, jfloat value) { + *reinterpret_cast<jfloat*>(address) = value; +} +static jdouble Unsafe_getDouble$(JNIEnv* env ATTRIBUTE_UNUSED, jobject, jlong address) { + return *reinterpret_cast<jdouble*>(address); +} + +static void Unsafe_putDouble$(JNIEnv* env ATTRIBUTE_UNUSED, jobject, jlong address, jdouble value) { + *reinterpret_cast<jdouble*>(address) = value; +} + +static void Unsafe_copyMemory(JNIEnv *env, jobject unsafe ATTRIBUTE_UNUSED, jlong src, + jlong dst, jlong size) { + if (size == 0) { + return; + } + // size is nonnegative and fits into size_t + if (size < 0 || size != (jlong)(size_t) size) { + ScopedFastNativeObjectAccess soa(env); + ThrowIllegalAccessException("wrong number of bytes"); + } + size_t sz = (size_t)size; + memcpy(reinterpret_cast<void *>(dst), reinterpret_cast<void *>(src), sz); +} + +template<typename T> +static void copyToArray(jlong srcAddr, mirror::PrimitiveArray<T>* array, + size_t array_offset, + size_t size) + SHARED_REQUIRES(Locks::mutator_lock_) { + const T* src = reinterpret_cast<T*>(srcAddr); + size_t sz = size / sizeof(T); + size_t of = array_offset / sizeof(T); + for (size_t i = 0; i < sz; ++i) { + array->Set(i + of, *(src + i)); + } +} + +template<typename T> +static void copyFromArray(jlong dstAddr, mirror::PrimitiveArray<T>* array, + size_t array_offset, + size_t size) + SHARED_REQUIRES(Locks::mutator_lock_) { + T* dst = reinterpret_cast<T*>(dstAddr); + size_t sz = size / sizeof(T); + size_t of = array_offset / sizeof(T); + for (size_t i = 0; i < sz; ++i) { + *(dst + i) = array->Get(i + of); + } +} + +static void Unsafe_copyMemoryToPrimitiveArray(JNIEnv *env, + jobject unsafe ATTRIBUTE_UNUSED, + jlong srcAddr, + jobject dstObj, + jlong dstOffset, + jlong size) { + ScopedObjectAccess soa(env); + if (size == 0) { + return; + } + // size is nonnegative and fits into size_t + if (size < 0 || size != (jlong)(size_t) size) { + ThrowIllegalAccessException("wrong number of bytes"); + } + size_t sz = (size_t)size; + size_t dst_offset = (size_t)dstOffset; + mirror::Object* dst = soa.Decode<mirror::Object*>(dstObj); + mirror::Class* component_type = dst->GetClass()->GetComponentType(); + if (component_type->IsPrimitiveByte() || component_type->IsPrimitiveBoolean()) { + copyToArray(srcAddr, dst->AsByteSizedArray(), dst_offset, sz); + } else if (component_type->IsPrimitiveShort() || component_type->IsPrimitiveChar()) { + copyToArray(srcAddr, dst->AsShortSizedArray(), dst_offset, sz); + } else if (component_type->IsPrimitiveInt() || component_type->IsPrimitiveFloat()) { + copyToArray(srcAddr, dst->AsIntArray(), dst_offset, sz); + } else if (component_type->IsPrimitiveLong() || component_type->IsPrimitiveDouble()) { + copyToArray(srcAddr, dst->AsLongArray(), dst_offset, sz); + } else { + ThrowIllegalAccessException("not a primitive array"); + } +} + +static void Unsafe_copyMemoryFromPrimitiveArray(JNIEnv *env, + jobject unsafe ATTRIBUTE_UNUSED, + jobject srcObj, + jlong srcOffset, + jlong dstAddr, + jlong size) { + ScopedObjectAccess soa(env); + if (size == 0) { + return; + } + // size is nonnegative and fits into size_t + if (size < 0 || size != (jlong)(size_t) size) { + ThrowIllegalAccessException("wrong number of bytes"); + } + size_t sz = (size_t)size; + size_t src_offset = (size_t)srcOffset; + mirror::Object* src = soa.Decode<mirror::Object*>(srcObj); + mirror::Class* component_type = src->GetClass()->GetComponentType(); + if (component_type->IsPrimitiveByte() || component_type->IsPrimitiveBoolean()) { + copyFromArray(dstAddr, src->AsByteSizedArray(), src_offset, sz); + } else if (component_type->IsPrimitiveShort() || component_type->IsPrimitiveChar()) { + copyFromArray(dstAddr, src->AsShortSizedArray(), src_offset, sz); + } else if (component_type->IsPrimitiveInt() || component_type->IsPrimitiveFloat()) { + copyFromArray(dstAddr, src->AsIntArray(), src_offset, sz); + } else if (component_type->IsPrimitiveLong() || component_type->IsPrimitiveDouble()) { + copyFromArray(dstAddr, src->AsLongArray(), src_offset, sz); + } else { + ThrowIllegalAccessException("not a primitive array"); + } +} +static jboolean Unsafe_getBoolean(JNIEnv* env, jobject, jobject javaObj, jlong offset) { + ScopedFastNativeObjectAccess soa(env); + mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj); + return obj->GetFieldBoolean(MemberOffset(offset)); +} + +static void Unsafe_putBoolean(JNIEnv* env, jobject, jobject javaObj, jlong offset, jboolean newValue) { + ScopedFastNativeObjectAccess soa(env); + mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj); + // JNI must use non transactional mode (SetField8 is non-transactional). + obj->SetFieldBoolean<false>(MemberOffset(offset), newValue); +} + +static jbyte Unsafe_getByte(JNIEnv* env, jobject, jobject javaObj, jlong offset) { + ScopedFastNativeObjectAccess soa(env); + mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj); + return obj->GetFieldByte(MemberOffset(offset)); +} + +static void Unsafe_putByte(JNIEnv* env, jobject, jobject javaObj, jlong offset, jbyte newValue) { + ScopedFastNativeObjectAccess soa(env); + mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj); + // JNI must use non transactional mode. + obj->SetFieldByte<false>(MemberOffset(offset), newValue); +} + +static jchar Unsafe_getChar(JNIEnv* env, jobject, jobject javaObj, jlong offset) { + ScopedFastNativeObjectAccess soa(env); + mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj); + return obj->GetFieldChar(MemberOffset(offset)); +} + +static void Unsafe_putChar(JNIEnv* env, jobject, jobject javaObj, jlong offset, jchar newValue) { + ScopedFastNativeObjectAccess soa(env); + mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj); + // JNI must use non transactional mode. + obj->SetFieldChar<false>(MemberOffset(offset), newValue); +} + +static jshort Unsafe_getShort(JNIEnv* env, jobject, jobject javaObj, jlong offset) { + ScopedFastNativeObjectAccess soa(env); + mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj); + return obj->GetFieldShort(MemberOffset(offset)); +} + +static void Unsafe_putShort(JNIEnv* env, jobject, jobject javaObj, jlong offset, jshort newValue) { + ScopedFastNativeObjectAccess soa(env); + mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj); + // JNI must use non transactional mode. + obj->SetFieldShort<false>(MemberOffset(offset), newValue); +} + +static jfloat Unsafe_getFloat(JNIEnv* env, jobject, jobject javaObj, jlong offset) { + ScopedFastNativeObjectAccess soa(env); + mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj); + union {int32_t val; jfloat converted;} conv; + conv.val = obj->GetField32(MemberOffset(offset)); + return conv.converted; +} + +static void Unsafe_putFloat(JNIEnv* env, jobject, jobject javaObj, jlong offset, jfloat newValue) { + ScopedFastNativeObjectAccess soa(env); + mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj); + union {int32_t converted; jfloat val;} conv; + conv.val = newValue; + // JNI must use non transactional mode. + obj->SetField32<false>(MemberOffset(offset), conv.converted); +} + +static jdouble Unsafe_getDouble(JNIEnv* env, jobject, jobject javaObj, jlong offset) { + ScopedFastNativeObjectAccess soa(env); + mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj); + union {int64_t val; jdouble converted;} conv; + conv.val = obj->GetField64(MemberOffset(offset)); + return conv.converted; +} + +static void Unsafe_putDouble(JNIEnv* env, jobject, jobject javaObj, jlong offset, jdouble newValue) { + ScopedFastNativeObjectAccess soa(env); + mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj); + union {int64_t converted; jdouble val;} conv; + conv.val = newValue; + // JNI must use non transactional mode. + obj->SetField64<false>(MemberOffset(offset), conv.converted); +} + static JNINativeMethod gMethods[] = { NATIVE_METHOD(Unsafe, compareAndSwapInt, "!(Ljava/lang/Object;JII)Z"), NATIVE_METHOD(Unsafe, compareAndSwapLong, "!(Ljava/lang/Object;JJJ)Z"), @@ -206,6 +483,40 @@ static JNINativeMethod gMethods[] = { NATIVE_METHOD(Unsafe, putOrderedObject, "!(Ljava/lang/Object;JLjava/lang/Object;)V"), NATIVE_METHOD(Unsafe, getArrayBaseOffsetForComponentType, "!(Ljava/lang/Class;)I"), NATIVE_METHOD(Unsafe, getArrayIndexScaleForComponentType, "!(Ljava/lang/Class;)I"), + NATIVE_METHOD(Unsafe, addressSize, "!()I"), + NATIVE_METHOD(Unsafe, pageSize, "!()I"), + NATIVE_METHOD(Unsafe, allocateMemory, "!(J)J"), + NATIVE_METHOD(Unsafe, freeMemory, "!(J)V"), + NATIVE_METHOD(Unsafe, setMemory, "!(JJB)V"), + NATIVE_METHOD(Unsafe, getByte$, "!(J)B"), + NATIVE_METHOD(Unsafe, putByte$, "!(JB)V"), + NATIVE_METHOD(Unsafe, getShort$, "!(J)S"), + NATIVE_METHOD(Unsafe, putShort$, "!(JS)V"), + NATIVE_METHOD(Unsafe, getChar$, "!(J)C"), + NATIVE_METHOD(Unsafe, putChar$, "!(JC)V"), + NATIVE_METHOD(Unsafe, getInt$, "!(J)I"), + NATIVE_METHOD(Unsafe, putInt$, "!(JI)V"), + NATIVE_METHOD(Unsafe, getLong$, "!(J)J"), + NATIVE_METHOD(Unsafe, putLong$, "!(JJ)V"), + NATIVE_METHOD(Unsafe, getFloat$, "!(J)F"), + NATIVE_METHOD(Unsafe, putFloat$, "!(JF)V"), + NATIVE_METHOD(Unsafe, getDouble$, "!(J)D"), + NATIVE_METHOD(Unsafe, putDouble$, "!(JD)V"), + NATIVE_METHOD(Unsafe, copyMemory, "!(JJJ)V"), + NATIVE_METHOD(Unsafe, copyMemoryToPrimitiveArray, "!(JLjava/lang/Object;JJ)V"), + NATIVE_METHOD(Unsafe, copyMemoryFromPrimitiveArray, "!(Ljava/lang/Object;JJJ)V"), + NATIVE_METHOD(Unsafe, getBoolean, "!(Ljava/lang/Object;J)Z"), + NATIVE_METHOD(Unsafe, getByte, "!(Ljava/lang/Object;J)B"), + NATIVE_METHOD(Unsafe, getChar, "!(Ljava/lang/Object;J)C"), + NATIVE_METHOD(Unsafe, getShort, "!(Ljava/lang/Object;J)S"), + NATIVE_METHOD(Unsafe, getFloat, "!(Ljava/lang/Object;J)F"), + NATIVE_METHOD(Unsafe, getDouble, "!(Ljava/lang/Object;J)D"), + NATIVE_METHOD(Unsafe, putBoolean, "!(Ljava/lang/Object;JZ)V"), + NATIVE_METHOD(Unsafe, putByte, "!(Ljava/lang/Object;JB)V"), + NATIVE_METHOD(Unsafe, putChar, "!(Ljava/lang/Object;JC)V"), + NATIVE_METHOD(Unsafe, putShort, "!(Ljava/lang/Object;JS)V"), + NATIVE_METHOD(Unsafe, putFloat, "!(Ljava/lang/Object;JF)V"), + NATIVE_METHOD(Unsafe, putDouble, "!(Ljava/lang/Object;JD)V"), }; void register_sun_misc_Unsafe(JNIEnv* env) { diff --git a/runtime/oat_file_assistant_test.cc b/runtime/oat_file_assistant_test.cc index 8c7efb2ea8..40cd50b02c 100644 --- a/runtime/oat_file_assistant_test.cc +++ b/runtime/oat_file_assistant_test.cc @@ -1025,7 +1025,7 @@ TEST_F(OatFileAssistantTest, RaceToGenerate) { // We use the lib core dex file, because it's large, and hopefully should // take a while to generate. - Copy(GetLibCoreDexFileName(), dex_location); + Copy(GetLibCoreDexFileNames()[0], dex_location); const int kNumThreads = 32; Thread* self = Thread::Current(); diff --git a/runtime/parsed_options_test.cc b/runtime/parsed_options_test.cc index 06b40fd925..b2240cb6a6 100644 --- a/runtime/parsed_options_test.cc +++ b/runtime/parsed_options_test.cc @@ -34,18 +34,28 @@ TEST_F(ParsedOptionsTest, ParsedOptions) { void* test_abort = reinterpret_cast<void*>(0xb); void* test_exit = reinterpret_cast<void*>(0xc); - std::string lib_core(CommonRuntimeTest::GetLibCoreDexFileName()); - std::string boot_class_path; + std::string class_path; boot_class_path += "-Xbootclasspath:"; - boot_class_path += lib_core; + + bool first_dex_file = true; + for (const std::string &dex_file_name : + CommonRuntimeTest::GetLibCoreDexFileNames()) { + if (!first_dex_file) { + class_path += ":"; + } else { + first_dex_file = false; + } + class_path += dex_file_name; + } + boot_class_path += class_path; RuntimeOptions options; options.push_back(std::make_pair(boot_class_path.c_str(), nullptr)); options.push_back(std::make_pair("-classpath", nullptr)); - options.push_back(std::make_pair(lib_core.c_str(), nullptr)); + options.push_back(std::make_pair(class_path.c_str(), nullptr)); options.push_back(std::make_pair("-cp", nullptr)); - options.push_back(std::make_pair(lib_core.c_str(), nullptr)); + options.push_back(std::make_pair(class_path.c_str(), nullptr)); options.push_back(std::make_pair("-Ximage:boot_image", nullptr)); options.push_back(std::make_pair("-Xcheck:jni", nullptr)); options.push_back(std::make_pair("-Xms2048", nullptr)); @@ -69,8 +79,8 @@ TEST_F(ParsedOptionsTest, ParsedOptions) { #define EXPECT_PARSED_EQ(expected, actual_key) EXPECT_EQ(expected, map.GetOrDefault(actual_key)) #define EXPECT_PARSED_EXISTS(actual_key) EXPECT_TRUE(map.Exists(actual_key)) - EXPECT_PARSED_EQ(lib_core, Opt::BootClassPath); - EXPECT_PARSED_EQ(lib_core, Opt::ClassPath); + EXPECT_PARSED_EQ(class_path, Opt::BootClassPath); + EXPECT_PARSED_EQ(class_path, Opt::ClassPath); EXPECT_PARSED_EQ(std::string("boot_image"), Opt::Image); EXPECT_PARSED_EXISTS(Opt::CheckJni); EXPECT_PARSED_EQ(2048U, Opt::MemoryInitialSize); diff --git a/runtime/runtime.cc b/runtime/runtime.cc index 93ca347b49..c7a5456efb 100644 --- a/runtime/runtime.cc +++ b/runtime/runtime.cc @@ -593,6 +593,7 @@ bool Runtime::Start() { PreInitializeNativeBridge("."); } InitNonZygoteOrPostFork(self->GetJniEnv(), + /* is_system_server */ false, NativeBridgeAction::kInitialize, GetInstructionSetString(kRuntimeISA)); } @@ -682,7 +683,8 @@ bool Runtime::InitZygote() { #endif } -void Runtime::InitNonZygoteOrPostFork(JNIEnv* env, NativeBridgeAction action, const char* isa) { +void Runtime::InitNonZygoteOrPostFork( + JNIEnv* env, bool is_system_server, NativeBridgeAction action, const char* isa) { is_zygote_ = false; if (is_native_bridge_loaded_) { @@ -704,7 +706,7 @@ void Runtime::InitNonZygoteOrPostFork(JNIEnv* env, NativeBridgeAction action, co // before fork aren't attributed to an app. heap_->ResetGcPerformanceInfo(); - if (!safe_mode_ && jit_options_->UseJIT() && jit_.get() == nullptr) { + if (!is_system_server && !safe_mode_ && jit_options_->UseJIT() && jit_.get() == nullptr) { // Note that when running ART standalone (not zygote, nor zygote fork), // the jit may have already been created. CreateJit(); @@ -1209,20 +1211,29 @@ void Runtime::InitNativeMethods() { // First set up JniConstants, which is used by both the runtime's built-in native // methods and libcore. JniConstants::init(env); - WellKnownClasses::Init(env); // Then set up the native methods provided by the runtime itself. RegisterRuntimeNativeMethods(env); - // Then set up libcore, which is just a regular JNI library with a regular JNI_OnLoad. - // Most JNI libraries can just use System.loadLibrary, but libcore can't because it's - // the library that implements System.loadLibrary! + // Initialize classes used in JNI. The initialization requires runtime native + // methods to be loaded first. + WellKnownClasses::Init(env); + + // Then set up libjavacore / libopenjdk, which are just a regular JNI libraries with + // a regular JNI_OnLoad. Most JNI libraries can just use System.loadLibrary, but + // libcore can't because it's the library that implements System.loadLibrary! { std::string error_msg; if (!java_vm_->LoadNativeLibrary(env, "libjavacore.so", nullptr, nullptr, nullptr, &error_msg)) { LOG(FATAL) << "LoadNativeLibrary failed for \"libjavacore.so\": " << error_msg; } } + { + std::string error_msg; + if (!java_vm_->LoadNativeLibrary(env, "libopenjdk.so", nullptr, nullptr, nullptr, &error_msg)) { + LOG(FATAL) << "LoadNativeLibrary failed for \"libopenjdk.so\": " << error_msg; + } + } // Initialize well known classes that may invoke runtime native methods. WellKnownClasses::LateInit(env); diff --git a/runtime/runtime.h b/runtime/runtime.h index 93d8fcfa46..7ca6b4f131 100644 --- a/runtime/runtime.h +++ b/runtime/runtime.h @@ -457,7 +457,8 @@ class Runtime { void PreZygoteFork(); bool InitZygote(); - void InitNonZygoteOrPostFork(JNIEnv* env, NativeBridgeAction action, const char* isa); + void InitNonZygoteOrPostFork( + JNIEnv* env, bool is_system_server, NativeBridgeAction action, const char* isa); const instrumentation::Instrumentation* GetInstrumentation() const { return &instrumentation_; diff --git a/runtime/well_known_classes.cc b/runtime/well_known_classes.cc index 2b778d9b22..2094b5fcd9 100644 --- a/runtime/well_known_classes.cc +++ b/runtime/well_known_classes.cc @@ -140,6 +140,7 @@ jfieldID WellKnownClasses::java_lang_Thread_priority; jfieldID WellKnownClasses::java_lang_Thread_uncaughtHandler; jfieldID WellKnownClasses::java_lang_Thread_nativePeer; jfieldID WellKnownClasses::java_lang_ThreadGroup_groups; +jfieldID WellKnownClasses::java_lang_ThreadGroup_ngroups; jfieldID WellKnownClasses::java_lang_ThreadGroup_mainThreadGroup; jfieldID WellKnownClasses::java_lang_ThreadGroup_name; jfieldID WellKnownClasses::java_lang_ThreadGroup_parent; @@ -268,7 +269,7 @@ void WellKnownClasses::Init(JNIEnv* env) { java_lang_Thread_init = CacheMethod(env, java_lang_Thread, false, "<init>", "(Ljava/lang/ThreadGroup;Ljava/lang/String;IZ)V"); java_lang_Thread_run = CacheMethod(env, java_lang_Thread, false, "run", "()V"); java_lang_Thread__UncaughtExceptionHandler_uncaughtException = CacheMethod(env, java_lang_Thread__UncaughtExceptionHandler, false, "uncaughtException", "(Ljava/lang/Thread;Ljava/lang/Throwable;)V"); - java_lang_ThreadGroup_removeThread = CacheMethod(env, java_lang_ThreadGroup, false, "removeThread", "(Ljava/lang/Thread;)V"); + java_lang_ThreadGroup_removeThread = CacheMethod(env, java_lang_ThreadGroup, false, "threadTerminated", "(Ljava/lang/Thread;)V"); java_nio_DirectByteBuffer_init = CacheMethod(env, java_nio_DirectByteBuffer, false, "<init>", "(JI)V"); libcore_reflect_AnnotationFactory_createAnnotation = CacheMethod(env, libcore_reflect_AnnotationFactory, true, "createAnnotation", "(Ljava/lang/Class;[Llibcore/reflect/AnnotationMember;)Ljava/lang/annotation/Annotation;"); libcore_reflect_AnnotationMember_init = CacheMethod(env, libcore_reflect_AnnotationMember, false, "<init>", "(Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Class;Ljava/lang/reflect/Method;)V"); @@ -340,9 +341,10 @@ void WellKnownClasses::Init(JNIEnv* env) { java_lang_Thread_lock = CacheField(env, java_lang_Thread, false, "lock", "Ljava/lang/Object;"); java_lang_Thread_name = CacheField(env, java_lang_Thread, false, "name", "Ljava/lang/String;"); java_lang_Thread_priority = CacheField(env, java_lang_Thread, false, "priority", "I"); - java_lang_Thread_uncaughtHandler = CacheField(env, java_lang_Thread, false, "uncaughtHandler", "Ljava/lang/Thread$UncaughtExceptionHandler;"); + java_lang_Thread_uncaughtHandler = CacheField(env, java_lang_Thread, false, "uncaughtExceptionHandler", "Ljava/lang/Thread$UncaughtExceptionHandler;"); java_lang_Thread_nativePeer = CacheField(env, java_lang_Thread, false, "nativePeer", "J"); - java_lang_ThreadGroup_groups = CacheField(env, java_lang_ThreadGroup, false, "groups", "Ljava/util/List;"); + java_lang_ThreadGroup_groups = CacheField(env, java_lang_ThreadGroup, false, "groups", "[Ljava/lang/ThreadGroup;"); + java_lang_ThreadGroup_ngroups = CacheField(env, java_lang_ThreadGroup, false, "ngroups", "I"); java_lang_ThreadGroup_mainThreadGroup = CacheField(env, java_lang_ThreadGroup, true, "mainThreadGroup", "Ljava/lang/ThreadGroup;"); java_lang_ThreadGroup_name = CacheField(env, java_lang_ThreadGroup, false, "name", "Ljava/lang/String;"); java_lang_ThreadGroup_parent = CacheField(env, java_lang_ThreadGroup, false, "parent", "Ljava/lang/ThreadGroup;"); @@ -350,13 +352,13 @@ void WellKnownClasses::Init(JNIEnv* env) { java_lang_Throwable_cause = CacheField(env, java_lang_Throwable, false, "cause", "Ljava/lang/Throwable;"); java_lang_Throwable_detailMessage = CacheField(env, java_lang_Throwable, false, "detailMessage", "Ljava/lang/String;"); java_lang_Throwable_stackTrace = CacheField(env, java_lang_Throwable, false, "stackTrace", "[Ljava/lang/StackTraceElement;"); - java_lang_Throwable_stackState = CacheField(env, java_lang_Throwable, false, "stackState", "Ljava/lang/Object;"); + java_lang_Throwable_stackState = CacheField(env, java_lang_Throwable, false, "backtrace", "Ljava/lang/Object;"); java_lang_Throwable_suppressedExceptions = CacheField(env, java_lang_Throwable, false, "suppressedExceptions", "Ljava/util/List;"); java_lang_reflect_AbstractMethod_artMethod = CacheField(env, java_lang_reflect_AbstractMethod, false, "artMethod", "J"); java_lang_reflect_Proxy_h = CacheField(env, java_lang_reflect_Proxy, false, "h", "Ljava/lang/reflect/InvocationHandler;"); java_nio_DirectByteBuffer_capacity = CacheField(env, java_nio_DirectByteBuffer, false, "capacity", "I"); - java_nio_DirectByteBuffer_effectiveDirectAddress = CacheField(env, java_nio_DirectByteBuffer, false, "effectiveDirectAddress", "J"); - java_util_ArrayList_array = CacheField(env, java_util_ArrayList, false, "array", "[Ljava/lang/Object;"); + java_nio_DirectByteBuffer_effectiveDirectAddress = CacheField(env, java_nio_DirectByteBuffer, false, "address", "J"); + java_util_ArrayList_array = CacheField(env, java_util_ArrayList, false, "elementData", "[Ljava/lang/Object;"); java_util_ArrayList_size = CacheField(env, java_util_ArrayList, false, "size", "I"); java_util_Collections_EMPTY_LIST = CacheField(env, java_util_Collections, true, "EMPTY_LIST", "Ljava/util/List;"); libcore_util_EmptyArray_STACK_TRACE_ELEMENT = CacheField(env, libcore_util_EmptyArray, true, "STACK_TRACE_ELEMENT", "[Ljava/lang/StackTraceElement;"); diff --git a/runtime/well_known_classes.h b/runtime/well_known_classes.h index c8562917e9..55158a77c6 100644 --- a/runtime/well_known_classes.h +++ b/runtime/well_known_classes.h @@ -153,6 +153,7 @@ struct WellKnownClasses { static jfieldID java_lang_Thread_uncaughtHandler; static jfieldID java_lang_Thread_nativePeer; static jfieldID java_lang_ThreadGroup_groups; + static jfieldID java_lang_ThreadGroup_ngroups; static jfieldID java_lang_ThreadGroup_mainThreadGroup; static jfieldID java_lang_ThreadGroup_name; static jfieldID java_lang_ThreadGroup_parent; diff --git a/runtime/zip_archive_test.cc b/runtime/zip_archive_test.cc index aded30cd86..4fc7ee2e20 100644 --- a/runtime/zip_archive_test.cc +++ b/runtime/zip_archive_test.cc @@ -32,7 +32,7 @@ class ZipArchiveTest : public CommonRuntimeTest {}; TEST_F(ZipArchiveTest, FindAndExtract) { std::string error_msg; - std::unique_ptr<ZipArchive> zip_archive(ZipArchive::Open(GetLibCoreDexFileName().c_str(), &error_msg)); + std::unique_ptr<ZipArchive> zip_archive(ZipArchive::Open(GetLibCoreDexFileNames()[0].c_str(), &error_msg)); ASSERT_TRUE(zip_archive.get() != nullptr) << error_msg; ASSERT_TRUE(error_msg.empty()); std::unique_ptr<ZipEntry> zip_entry(zip_archive->Find("classes.dex", &error_msg)); diff --git a/test/003-omnibus-opcodes/expected.txt b/test/003-omnibus-opcodes/expected.txt index b591a7a024..ee25ec10e6 100644 --- a/test/003-omnibus-opcodes/expected.txt +++ b/test/003-omnibus-opcodes/expected.txt @@ -31,15 +31,7 @@ FloatMath.doubleOperTest FloatMath.checkConvI FloatMath.checkConvL FloatMath.checkConvF - 0: -2.0054409E9 - 1: -8.613303E18 - 2: -3.1415927 --2.0054409E9, -8.6133031E18, -3.1415927 FloatMath.checkConvD - 0: -2.005440939E9 - 1: -8.613303245920329E18 - 2: 123.45600128173828 --2.005440939E9, -8.6133032459203287E18, 123.4560012817382 FloatMath.checkConsts FloatMath.jlmTests IntMath.testIntCompare diff --git a/test/003-omnibus-opcodes/src/FloatMath.java b/test/003-omnibus-opcodes/src/FloatMath.java index a0bc9f46dd..96befe9cdc 100644 --- a/test/003-omnibus-opcodes/src/FloatMath.java +++ b/test/003-omnibus-opcodes/src/FloatMath.java @@ -245,10 +245,9 @@ public class FloatMath { } static void checkConvF(float[] results) { System.out.println("FloatMath.checkConvF"); - // TODO: Main.assertTrue values - for (int i = 0; i < results.length; i++) - System.out.println(" " + i + ": " + results[i]); - System.out.println("-2.0054409E9, -8.6133031E18, -3.1415927"); + Main.assertTrue(results[0] == -2.0054409E9f); + Main.assertTrue(results[1] == -8.613303E18f); + Main.assertTrue(results[2] == -3.1415927f); } static double[] convD(int i, long l, float f) { @@ -260,10 +259,9 @@ public class FloatMath { } static void checkConvD(double[] results) { System.out.println("FloatMath.checkConvD"); - // TODO: Main.assertTrue values - for (int i = 0; i < results.length; i++) - System.out.println(" " + i + ": " + results[i]); - System.out.println("-2.005440939E9, -8.6133032459203287E18, 123.4560012817382"); + Main.assertTrue(results[0] == -2.005440939E9); + Main.assertTrue(results[1] == -8.6133032459203287E18); + Main.assertTrue(results[2] == 123.45600128173828); } static void checkConsts() { diff --git a/test/031-class-attributes/expected.txt b/test/031-class-attributes/expected.txt index de99872b52..72656ae916 100644 --- a/test/031-class-attributes/expected.txt +++ b/test/031-class-attributes/expected.txt @@ -84,7 +84,7 @@ abstract final [LClassAttrs$PackagePrivateInnerInterface; enclosingCon: null enclosingMeth: null modifiers: 1 - package: package otherpackage + package: package otherpackage, Unknown, version 0.0 declaredClasses: [0] member classes: [0] isAnnotation: false diff --git a/test/034-call-null/expected.txt b/test/034-call-null/expected.txt index 343226f705..4e0281e556 100644 --- a/test/034-call-null/expected.txt +++ b/test/034-call-null/expected.txt @@ -1,2 +1,2 @@ -java.lang.NullPointerException: Attempt to invoke direct method 'void Main.doStuff(int, int[][], java.lang.String, java.lang.String[][])' on a null object reference +Exception in thread "main" java.lang.NullPointerException: Attempt to invoke direct method 'void Main.doStuff(int, int[][], java.lang.String, java.lang.String[][])' on a null object reference at Main.main(Main.java:26) diff --git a/test/038-inner-null/expected.txt b/test/038-inner-null/expected.txt index ba411f030c..2e925644e3 100644 --- a/test/038-inner-null/expected.txt +++ b/test/038-inner-null/expected.txt @@ -1,4 +1,4 @@ new Special() -java.lang.NullPointerException: Attempt to invoke virtual method 'void Main$Blort.repaint()' on a null object reference +Exception in thread "main" java.lang.NullPointerException: Attempt to invoke virtual method 'void Main$Blort.repaint()' on a null object reference at Main$Special.callInner(Main.java:31) at Main.main(Main.java:20) diff --git a/test/042-new-instance/expected.txt b/test/042-new-instance/expected.txt index 7d843d1b3f..c5de313baf 100644 --- a/test/042-new-instance/expected.txt +++ b/test/042-new-instance/expected.txt @@ -9,3 +9,4 @@ Cons StaticInnerClass succeeded Cons got expected PackageAccess complaint Cons got expected InstantationException Cons got expected PackageAccess2 complaint +Cons ConstructorAccess succeeded diff --git a/test/042-new-instance/src/Main.java b/test/042-new-instance/src/Main.java index b0a5fd4f66..8cd6b2ee7d 100644 --- a/test/042-new-instance/src/Main.java +++ b/test/042-new-instance/src/Main.java @@ -156,6 +156,14 @@ public class Main { ex.printStackTrace(); } + // should succeed + try { + otherpackage.ConstructorAccess.newConstructorInstance(); + System.out.println("Cons ConstructorAccess succeeded"); + } catch (Exception ex) { + System.err.println("Cons ConstructorAccess failed"); + ex.printStackTrace(); + } } class InnerClass { @@ -173,7 +181,6 @@ class LocalClass2 { public LocalClass2() {} } - class LocalClass3 { public static void main() { try { diff --git a/test/042-new-instance/src/otherpackage/ConstructorAccess.java b/test/042-new-instance/src/otherpackage/ConstructorAccess.java new file mode 100644 index 0000000000..a74e9a0650 --- /dev/null +++ b/test/042-new-instance/src/otherpackage/ConstructorAccess.java @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2015 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. + */ + +package otherpackage; + +import java.lang.reflect.Constructor; + +public class ConstructorAccess { + + static class Inner { + Inner() {} + } + + // Test for regression in b/25817515. Inner class constructor should + // be accessible from this static method, but if we over-shoot and check + // accessibility using the frame below (in Main class), we will see an + // IllegalAccessException from #newInstance + static public void newConstructorInstance() throws Exception { + Class c = Inner.class; + Constructor cons = c.getDeclaredConstructor((Class[]) null); + Object obj = cons.newInstance(); + } +} diff --git a/test/046-reflect/expected.txt b/test/046-reflect/expected.txt index d657d44e61..06932b9671 100644 --- a/test/046-reflect/expected.txt +++ b/test/046-reflect/expected.txt @@ -96,8 +96,8 @@ got expected exception for Class.newInstance got expected exception for Constructor.newInstance ReflectTest done! public method -static java.lang.Object java.util.Collections.checkType(java.lang.Object,java.lang.Class) accessible=false -static java.lang.Object java.util.Collections.checkType(java.lang.Object,java.lang.Class) accessible=true +private static void java.util.Collections.swap(java.lang.Object[],int,int) accessible=false +private static void java.util.Collections.swap(java.lang.Object[],int,int) accessible=true checkType invoking null checkType got expected exception calling const-class FieldNoisyInitUser.class diff --git a/test/046-reflect/src/Main.java b/test/046-reflect/src/Main.java index 0c90109c69..67a0d110ac 100644 --- a/test/046-reflect/src/Main.java +++ b/test/046-reflect/src/Main.java @@ -407,12 +407,13 @@ public class Main { System.out.println("ReflectTest done!"); } - public static void checkType() { + public static void checkSwap() { Method m; + final Object[] objects = new Object[2]; try { - m = Collections.class.getDeclaredMethod("checkType", - Object.class, Class.class); + m = Collections.class.getDeclaredMethod("swap", + Object[].class, int.class, int.class); } catch (NoSuchMethodException nsme) { nsme.printStackTrace(); return; @@ -421,7 +422,7 @@ public class Main { m.setAccessible(true); System.out.println(m + " accessible=" + m.isAccessible()); try { - m.invoke(null, new Object(), Object.class); + m.invoke(null, objects, 0, 1); } catch (IllegalAccessException iae) { iae.printStackTrace(); return; @@ -432,7 +433,7 @@ public class Main { try { String s = "Should be ignored"; - m.invoke(s, new Object(), Object.class); + m.invoke(s, objects, 0, 1); } catch (IllegalAccessException iae) { iae.printStackTrace(); return; @@ -443,7 +444,8 @@ public class Main { try { System.out.println("checkType invoking null"); - m.invoke(null, new Object(), int.class); + // Trigger an NPE at the target. + m.invoke(null, null, 0, 1); System.out.println("ERROR: should throw InvocationTargetException"); } catch (InvocationTargetException ite) { System.out.println("checkType got expected exception"); @@ -710,27 +712,27 @@ public class Main { private static void checkGetDeclaredConstructor() { try { Method.class.getDeclaredConstructor().setAccessible(true); - System.out.print("Didn't get an exception from Method.class.getDeclaredConstructor().setAccessible"); + System.out.println("Didn't get an exception from Method.class.getDeclaredConstructor().setAccessible"); } catch (SecurityException e) { } catch (NoSuchMethodException e) { } catch (Exception e) { - System.out.print(e); + System.out.println(e); } try { Field.class.getDeclaredConstructor().setAccessible(true); - System.out.print("Didn't get an exception from Field.class.getDeclaredConstructor().setAccessible"); + System.out.println("Didn't get an exception from Field.class.getDeclaredConstructor().setAccessible"); } catch (SecurityException e) { } catch (NoSuchMethodException e) { } catch (Exception e) { - System.out.print(e); + System.out.println(e); } try { Class.class.getDeclaredConstructor().setAccessible(true); - System.out.print("Didn't get an exception from Class.class.getDeclaredConstructor().setAccessible"); + System.out.println("Didn't get an exception from Class.class.getDeclaredConstructor().setAccessible"); } catch (SecurityException e) { } catch (NoSuchMethodException e) { } catch (Exception e) { - System.out.print(e); + System.out.println(e); } } @@ -744,7 +746,7 @@ public class Main { checkGetDeclaredConstructor(); checkAccess(); - checkType(); + checkSwap(); checkClinitForFields(); checkClinitForMethods(); checkGeneric(); diff --git a/test/055-enum-performance/src/Main.java b/test/055-enum-performance/src/Main.java index d5903af697..d6bb21145f 100644 --- a/test/055-enum-performance/src/Main.java +++ b/test/055-enum-performance/src/Main.java @@ -20,7 +20,7 @@ public class Main { throw new AssertionError(); } catch (InvocationTargetException expected) { IllegalArgumentException iae = (IllegalArgumentException) expected.getCause(); - if (!iae.getMessage().equals("class java.lang.String is not an enum type")) { + if (!iae.getMessage().equals("class java.lang.String is not an enum type.")) { throw new AssertionError(); } } diff --git a/test/063-process-manager/expected.txt b/test/063-process-manager/expected.txt index 8360239777..8c01bf01dd 100644 --- a/test/063-process-manager/expected.txt +++ b/test/063-process-manager/expected.txt @@ -4,12 +4,12 @@ spawning child #1 spawning child process manager: RUNNABLE child died -process manager: WAITING +process manager: TIMED_WAITING spawning child #2 spawning child process manager: RUNNABLE child died -process manager: WAITING +process manager: TIMED_WAITING done! diff --git a/test/063-process-manager/src/Main.java b/test/063-process-manager/src/Main.java index 68bf878505..e9e522c3ff 100644 --- a/test/063-process-manager/src/Main.java +++ b/test/063-process-manager/src/Main.java @@ -30,7 +30,7 @@ public class Main { traces.entrySet()) { Thread t = entry.getKey(); String name = t.getName(); - if (name.equals("java.lang.ProcessManager")) { + if (name.indexOf("process reaper") >= 0) { System.out.println("process manager: " + t.getState()); found = true; } diff --git a/test/082-inline-execute/src/Main.java b/test/082-inline-execute/src/Main.java index 5913c40b36..af25d9bc54 100644 --- a/test/082-inline-execute/src/Main.java +++ b/test/082-inline-execute/src/Main.java @@ -803,7 +803,7 @@ public class Main { Assert.assertEquals(Math.round(-2.5d), -2l); Assert.assertEquals(Math.round(-2.9d), -3l); Assert.assertEquals(Math.round(-3.0d), -3l); - Assert.assertEquals(Math.round(0.49999999999999994d), 1l); + Assert.assertEquals(Math.round(0.49999999999999994d), 0l); Assert.assertEquals(Math.round(Double.NaN), (long)+0.0d); Assert.assertEquals(Math.round(Long.MAX_VALUE + 1.0d), Long.MAX_VALUE); Assert.assertEquals(Math.round(Long.MIN_VALUE - 1.0d), Long.MIN_VALUE); @@ -1034,7 +1034,7 @@ public class Main { Assert.assertEquals(StrictMath.round(-2.5d), -2l); Assert.assertEquals(StrictMath.round(-2.9d), -3l); Assert.assertEquals(StrictMath.round(-3.0d), -3l); - Assert.assertEquals(StrictMath.round(0.49999999999999994d), 1l); + Assert.assertEquals(StrictMath.round(0.49999999999999994d), 0l); Assert.assertEquals(StrictMath.round(Double.NaN), (long)+0.0d); Assert.assertEquals(StrictMath.round(Long.MAX_VALUE + 1.0d), Long.MAX_VALUE); Assert.assertEquals(StrictMath.round(Long.MIN_VALUE - 1.0d), Long.MIN_VALUE); diff --git a/test/100-reflect2/expected.txt b/test/100-reflect2/expected.txt index 0b87a4f311..e4988c9b5f 100644 --- a/test/100-reflect2/expected.txt +++ b/test/100-reflect2/expected.txt @@ -32,8 +32,8 @@ z (class java.lang.Character) 62 (class java.lang.Long) 14 (class java.lang.Short) [java.lang.String(int,int,char[]), public java.lang.String(), public java.lang.String(byte[]), public java.lang.String(byte[],int), public java.lang.String(byte[],int,int), public java.lang.String(byte[],int,int,int), public java.lang.String(byte[],int,int,java.lang.String) throws java.io.UnsupportedEncodingException, public java.lang.String(byte[],int,int,java.nio.charset.Charset), public java.lang.String(byte[],java.lang.String) throws java.io.UnsupportedEncodingException, public java.lang.String(byte[],java.nio.charset.Charset), public java.lang.String(char[]), public java.lang.String(char[],int,int), public java.lang.String(int[],int,int), public java.lang.String(java.lang.String), public java.lang.String(java.lang.StringBuffer), public java.lang.String(java.lang.StringBuilder)] -[private final int java.lang.String.count, private int java.lang.String.hashCode, private static final char java.lang.String.REPLACEMENT_CHAR, private static final char[] java.lang.String.ASCII, private static final long java.lang.String.serialVersionUID, public static final java.util.Comparator java.lang.String.CASE_INSENSITIVE_ORDER] -[native void java.lang.String.getCharsNoCheck(int,int,char[],int), native void java.lang.String.setCharAt(int,char), private char java.lang.String.foldCase(char), private int java.lang.String.indexOfSupplementary(int,int), private int java.lang.String.lastIndexOfSupplementary(int,int), private java.lang.StringIndexOutOfBoundsException java.lang.String.failedBoundsCheck(int,int,int), private java.lang.StringIndexOutOfBoundsException java.lang.String.indexAndLength(int), private java.lang.StringIndexOutOfBoundsException java.lang.String.startEndAndLength(int,int), private native int java.lang.String.fastIndexOf(int,int), private native java.lang.String java.lang.String.fastSubstring(int,int), private static int java.lang.String.indexOf(java.lang.String,java.lang.String,int,int,char), public [B java.lang.String.getBytes(), public [B java.lang.String.getBytes(java.lang.String) throws java.io.UnsupportedEncodingException, public [B java.lang.String.getBytes(java.nio.charset.Charset), public [Ljava.lang.String; java.lang.String.split(java.lang.String), public [Ljava.lang.String; java.lang.String.split(java.lang.String,int), public boolean java.lang.String.contains(java.lang.CharSequence), public boolean java.lang.String.contentEquals(java.lang.CharSequence), public boolean java.lang.String.contentEquals(java.lang.StringBuffer), public boolean java.lang.String.endsWith(java.lang.String), public boolean java.lang.String.equals(java.lang.Object), public boolean java.lang.String.equalsIgnoreCase(java.lang.String), public boolean java.lang.String.isEmpty(), public boolean java.lang.String.matches(java.lang.String), public boolean java.lang.String.regionMatches(boolean,int,java.lang.String,int,int), public boolean java.lang.String.regionMatches(int,java.lang.String,int,int), public boolean java.lang.String.startsWith(java.lang.String), public boolean java.lang.String.startsWith(java.lang.String,int), public int java.lang.String.codePointAt(int), public int java.lang.String.codePointBefore(int), public int java.lang.String.codePointCount(int,int), public int java.lang.String.compareTo(java.lang.Object), public int java.lang.String.compareToIgnoreCase(java.lang.String), public int java.lang.String.hashCode(), public int java.lang.String.indexOf(int), public int java.lang.String.indexOf(int,int), public int java.lang.String.indexOf(java.lang.String), public int java.lang.String.indexOf(java.lang.String,int), public int java.lang.String.lastIndexOf(int), public int java.lang.String.lastIndexOf(int,int), public int java.lang.String.lastIndexOf(java.lang.String), public int java.lang.String.lastIndexOf(java.lang.String,int), public int java.lang.String.length(), public int java.lang.String.offsetByCodePoints(int,int), public java.lang.CharSequence java.lang.String.subSequence(int,int), public java.lang.String java.lang.String.replace(char,char), public java.lang.String java.lang.String.replace(java.lang.CharSequence,java.lang.CharSequence), public java.lang.String java.lang.String.replaceAll(java.lang.String,java.lang.String), public java.lang.String java.lang.String.replaceFirst(java.lang.String,java.lang.String), public java.lang.String java.lang.String.substring(int), public java.lang.String java.lang.String.substring(int,int), public java.lang.String java.lang.String.toLowerCase(), public java.lang.String java.lang.String.toLowerCase(java.util.Locale), public java.lang.String java.lang.String.toString(), public java.lang.String java.lang.String.toUpperCase(), public java.lang.String java.lang.String.toUpperCase(java.util.Locale), public java.lang.String java.lang.String.trim(), public native [C java.lang.String.toCharArray(), public native char java.lang.String.charAt(int), public native int java.lang.String.compareTo(java.lang.String), public native java.lang.String java.lang.String.concat(java.lang.String), public native java.lang.String java.lang.String.intern(), public static java.lang.String java.lang.String.copyValueOf(char[]), public static java.lang.String java.lang.String.copyValueOf(char[],int,int), public static java.lang.String java.lang.String.format(java.lang.String,java.lang.Object[]), public static java.lang.String java.lang.String.format(java.util.Locale,java.lang.String,java.lang.Object[]), public static java.lang.String java.lang.String.valueOf(boolean), public static java.lang.String java.lang.String.valueOf(char), public static java.lang.String java.lang.String.valueOf(char[]), public static java.lang.String java.lang.String.valueOf(char[],int,int), public static java.lang.String java.lang.String.valueOf(double), public static java.lang.String java.lang.String.valueOf(float), public static java.lang.String java.lang.String.valueOf(int), public static java.lang.String java.lang.String.valueOf(java.lang.Object), public static java.lang.String java.lang.String.valueOf(long), public void java.lang.String.getBytes(int,int,byte[],int), public void java.lang.String.getChars(int,int,char[],int)] +[private final int java.lang.String.count, private int java.lang.String.hash, private static final java.io.ObjectStreamField[] java.lang.String.serialPersistentFields, private static final long java.lang.String.serialVersionUID, private static int java.lang.String.HASHING_SEED, public static final java.util.Comparator java.lang.String.CASE_INSENSITIVE_ORDER] +[int java.lang.String.hash32(), native void java.lang.String.getCharsNoCheck(int,int,char[],int), native void java.lang.String.setCharAt(int,char), private int java.lang.String.indexOfSupplementary(int,int), private int java.lang.String.lastIndexOfSupplementary(int,int), private native int java.lang.String.fastIndexOf(int,int), private native java.lang.String java.lang.String.fastSubstring(int,int), private static int java.lang.String.getHashingSeed(), public boolean java.lang.String.contains(java.lang.CharSequence), public boolean java.lang.String.contentEquals(java.lang.CharSequence), public boolean java.lang.String.contentEquals(java.lang.StringBuffer), public boolean java.lang.String.endsWith(java.lang.String), public boolean java.lang.String.equals(java.lang.Object), public boolean java.lang.String.equalsIgnoreCase(java.lang.String), public boolean java.lang.String.isEmpty(), public boolean java.lang.String.matches(java.lang.String), public boolean java.lang.String.regionMatches(boolean,int,java.lang.String,int,int), public boolean java.lang.String.regionMatches(int,java.lang.String,int,int), public boolean java.lang.String.startsWith(java.lang.String), public boolean java.lang.String.startsWith(java.lang.String,int), public byte[] java.lang.String.getBytes(), public byte[] java.lang.String.getBytes(java.lang.String) throws java.io.UnsupportedEncodingException, public byte[] java.lang.String.getBytes(java.nio.charset.Charset), public int java.lang.String.codePointAt(int), public int java.lang.String.codePointBefore(int), public int java.lang.String.codePointCount(int,int), public int java.lang.String.compareTo(java.lang.Object), public int java.lang.String.compareToIgnoreCase(java.lang.String), public int java.lang.String.hashCode(), public int java.lang.String.indexOf(int), public int java.lang.String.indexOf(int,int), public int java.lang.String.indexOf(java.lang.String), public int java.lang.String.indexOf(java.lang.String,int), public int java.lang.String.lastIndexOf(int), public int java.lang.String.lastIndexOf(int,int), public int java.lang.String.lastIndexOf(java.lang.String), public int java.lang.String.lastIndexOf(java.lang.String,int), public int java.lang.String.length(), public int java.lang.String.offsetByCodePoints(int,int), public java.lang.CharSequence java.lang.String.subSequence(int,int), public java.lang.String java.lang.String.replace(char,char), public java.lang.String java.lang.String.replace(java.lang.CharSequence,java.lang.CharSequence), public java.lang.String java.lang.String.replaceAll(java.lang.String,java.lang.String), public java.lang.String java.lang.String.replaceFirst(java.lang.String,java.lang.String), public java.lang.String java.lang.String.substring(int), public java.lang.String java.lang.String.substring(int,int), public java.lang.String java.lang.String.toLowerCase(), public java.lang.String java.lang.String.toLowerCase(java.util.Locale), public java.lang.String java.lang.String.toString(), public java.lang.String java.lang.String.toUpperCase(), public java.lang.String java.lang.String.toUpperCase(java.util.Locale), public java.lang.String java.lang.String.trim(), public java.lang.String[] java.lang.String.split(java.lang.String), public java.lang.String[] java.lang.String.split(java.lang.String,int), public native char java.lang.String.charAt(int), public native char[] java.lang.String.toCharArray(), public native int java.lang.String.compareTo(java.lang.String), public native java.lang.String java.lang.String.concat(java.lang.String), public native java.lang.String java.lang.String.intern(), public static java.lang.String java.lang.String.copyValueOf(char[]), public static java.lang.String java.lang.String.copyValueOf(char[],int,int), public static java.lang.String java.lang.String.format(java.lang.String,java.lang.Object[]), public static java.lang.String java.lang.String.format(java.util.Locale,java.lang.String,java.lang.Object[]), public static java.lang.String java.lang.String.valueOf(boolean), public static java.lang.String java.lang.String.valueOf(char), public static java.lang.String java.lang.String.valueOf(char[]), public static java.lang.String java.lang.String.valueOf(char[],int,int), public static java.lang.String java.lang.String.valueOf(double), public static java.lang.String java.lang.String.valueOf(float), public static java.lang.String java.lang.String.valueOf(int), public static java.lang.String java.lang.String.valueOf(java.lang.Object), public static java.lang.String java.lang.String.valueOf(long), public void java.lang.String.getBytes(int,int,byte[],int), public void java.lang.String.getChars(int,int,char[],int), static int java.lang.String.indexOf(char[],int,int,char[],int,int,int), static int java.lang.String.indexOf(java.lang.String,java.lang.String,int), static int java.lang.String.lastIndexOf(char[],int,int,char[],int,int,int), static int java.lang.String.lastIndexOf(java.lang.String,java.lang.String,int)] [] [interface java.io.Serializable, interface java.lang.Comparable, interface java.lang.CharSequence] 0 diff --git a/test/137-cfi/src/Main.java b/test/137-cfi/src/Main.java index dc3ef7eb07..5474c9b7b6 100644 --- a/test/137-cfi/src/Main.java +++ b/test/137-cfi/src/Main.java @@ -117,7 +117,7 @@ public class Main implements Comparator<Main> { // Could do reflection for the private pid field, but String parsing is easier. String s = p.toString(); if (s.startsWith("Process[pid=")) { - return Integer.parseInt(s.substring("Process[pid=".length(), s.length() - 1)); + return Integer.parseInt(s.substring("Process[pid=".length(), s.indexOf(","))); } else { return -1; } diff --git a/test/Android.run-test.mk b/test/Android.run-test.mk index 54ceb753fe..f0ee921891 100644 --- a/test/Android.run-test.mk +++ b/test/Android.run-test.mk @@ -637,14 +637,16 @@ ART_TEST_HOST_RUN_TEST_DEPENDENCIES := \ $(ART_HOST_OUT_SHARED_LIBRARIES)/libarttest$(ART_HOST_SHLIB_EXTENSION) \ $(ART_HOST_OUT_SHARED_LIBRARIES)/libarttestd$(ART_HOST_SHLIB_EXTENSION) \ $(ART_HOST_OUT_SHARED_LIBRARIES)/libnativebridgetest$(ART_HOST_SHLIB_EXTENSION) \ - $(ART_HOST_OUT_SHARED_LIBRARIES)/libjavacore$(ART_HOST_SHLIB_EXTENSION) + $(ART_HOST_OUT_SHARED_LIBRARIES)/libjavacore$(ART_HOST_SHLIB_EXTENSION) \ + $(ART_HOST_OUT_SHARED_LIBRARIES)/libopenjdk$(ART_HOST_SHLIB_EXTENSION) ifneq ($(HOST_PREFER_32_BIT),true) ART_TEST_HOST_RUN_TEST_DEPENDENCIES += \ $(2ND_ART_HOST_OUT_SHARED_LIBRARIES)/libarttest$(ART_HOST_SHLIB_EXTENSION) \ $(2ND_ART_HOST_OUT_SHARED_LIBRARIES)/libarttestd$(ART_HOST_SHLIB_EXTENSION) \ $(2ND_ART_HOST_OUT_SHARED_LIBRARIES)/libnativebridgetest$(ART_HOST_SHLIB_EXTENSION) \ - $(2ND_ART_HOST_OUT_SHARED_LIBRARIES)/libjavacore$(ART_HOST_SHLIB_EXTENSION) + $(2ND_ART_HOST_OUT_SHARED_LIBRARIES)/libjavacore$(ART_HOST_SHLIB_EXTENSION) \ + $(2ND_ART_HOST_OUT_SHARED_LIBRARIES)/libopenjdk$(ART_HOST_SHLIB_EXTENSION) endif # Create a rule to build and run a tests following the form: diff --git a/test/run-test b/test/run-test index 60e008c8bb..ac2b52c28c 100755 --- a/test/run-test +++ b/test/run-test @@ -85,7 +85,7 @@ fi # If JACK_CLASSPATH is not set, assume it only contains core-libart. if [ -z "$JACK_CLASSPATH" ]; then - export JACK_CLASSPATH="${OUT_DIR:-$ANDROID_BUILD_TOP/out}/host/common/obj/JAVA_LIBRARIES/core-libart-hostdex_intermediates/classes.jack" + export JACK_CLASSPATH="${OUT_DIR:-$ANDROID_BUILD_TOP/out}/host/common/obj/JAVA_LIBRARIES/core-libart-hostdex_intermediates/classes.jack:${OUT_DIR:-$ANDROID_BUILD_TOP/out}/host/common/obj/JAVA_LIBRARIES/core-oj-hostdex_intermediates/classes.jack" fi # If JILL_JAR is not set, assume it is located in the prebuilts directory. @@ -458,7 +458,7 @@ fi if [ "$runtime" = "dalvik" ]; then if [ "$target_mode" = "no" ]; then framework="${ANDROID_PRODUCT_OUT}/system/framework" - bpath="${framework}/core.jar:${framework}/conscrypt.jar:${framework}/okhttp.jar:${framework}/core-junit.jar:${framework}/bouncycastle.jar:${framework}/ext.jar" + bpath="${framework}/core-libart.jar:${framework}/core-oj.jar:${framework}/conscrypt.jar:${framework}/okhttp.jar:${framework}/core-junit.jar:${framework}/bouncycastle.jar:${framework}/ext.jar" run_args="${run_args} --boot -Xbootclasspath:${bpath}" else true # defaults to using target BOOTCLASSPATH @@ -502,6 +502,7 @@ if [ "$have_image" = "no" ]; then # TODO If the target was compiled WITH_DEXPREOPT=true then these tests will # fail since these jar files will be stripped. bpath="${framework}/core-libart${bpath_suffix}.jar" + bpath="${bpath}:${framework}/core-oj${bpath_suffix}.jar" bpath="${bpath}:${framework}/conscrypt${bpath_suffix}.jar" bpath="${bpath}:${framework}/okhttp${bpath_suffix}.jar" bpath="${bpath}:${framework}/core-junit${bpath_suffix}.jar" |