diff options
author | 2015-11-12 11:49:06 +0000 | |
---|---|---|
committer | 2015-11-12 11:52:42 +0000 | |
commit | d1ef4362bf799f9f5d50e5edef8433664b503051 (patch) | |
tree | 59aaa140925efa790f787d5e1caf6d0cafd6ae15 | |
parent | e4cf5892c2a244034900d49499c071b255571bba (diff) | |
parent | f32e8327da5dd33abe18662fbca5e584cd047816 (diff) |
Merge lmp changes into mnc.
Most merge conflicts are due to changes in the string representation.
They have been resolved in favour of "mnc-dev" since we've changed
the string representation there. Other changes relate to the
fact that there are now two jars in libcore (core-oj and core-libart).
Change-Id: I1fcc6e5f8dab8d1954dcddca0493563e7677d433
-rw-r--r-- | Android.mk | 9 | ||||
-rw-r--r-- | build/Android.common_path.mk | 2 | ||||
-rw-r--r-- | compiler/image_test.cc | 2 | ||||
-rw-r--r-- | runtime/Android.mk | 1 | ||||
-rw-r--r-- | runtime/asm_support.h | 8 | ||||
-rw-r--r-- | runtime/class_linker.cc | 2 | ||||
-rw-r--r-- | runtime/class_linker_test.cc | 7 | ||||
-rw-r--r-- | runtime/common_runtime_test.cc | 11 | ||||
-rw-r--r-- | runtime/common_runtime_test.h | 4 | ||||
-rw-r--r-- | runtime/dex_file_test.cc | 2 | ||||
-rw-r--r-- | runtime/mirror/class.h | 15 | ||||
-rw-r--r-- | runtime/mirror/reference-inl.h | 2 | ||||
-rw-r--r-- | runtime/mirror/string-inl.h | 4 | ||||
-rw-r--r-- | runtime/mirror/throwable.cc | 4 | ||||
-rw-r--r-- | runtime/mirror/throwable.h | 4 | ||||
-rw-r--r-- | runtime/native/OpenjdkJvm.cc | 616 | ||||
-rw-r--r-- | runtime/native/java_lang_System.cc | 129 | ||||
-rw-r--r-- | runtime/native/sun_misc_Unsafe.cc | 318 | ||||
-rw-r--r-- | runtime/oat_file_assistant_test.cc | 2 | ||||
-rw-r--r-- | runtime/parsed_options_test.cc | 24 | ||||
-rw-r--r-- | runtime/runtime.cc | 12 | ||||
-rw-r--r-- | runtime/well_known_classes.cc | 12 | ||||
-rw-r--r-- | runtime/zip_archive_test.cc | 2 |
23 files changed, 1013 insertions, 179 deletions
diff --git a/Android.mk b/Android.mk index 3467f1d062..a2cc09291e 100644 --- a/Android.mk +++ b/Android.mk @@ -93,13 +93,18 @@ 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)/libxxavacore$(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)/libxxavacore.so ifdef TARGET_2ND_ARCH ART_TARGET_DEPENDENCIES += $(2ND_TARGET_OUT_SHARED_LIBRARIES)/libjavacore.so +ART_TARGET_DEPENDENCIES += $(2ND_TARGET_OUT_SHARED_LIBRARIES)/libxxavacore.so endif ifdef HOST_2ND_ARCH ART_HOST_DEPENDENCIES += $(2ND_HOST_OUT_SHARED_LIBRARIES)/libjavacore.so diff --git a/build/Android.common_path.mk b/build/Android.common_path.mk index b9a449c89b..8c2e7f9e59 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 core-junit bouncycastle +TARGET_CORE_JARS := core-oj core-libart conscrypt okhttp core-junit bouncycastle HOST_CORE_JARS := $(addsuffix -hostdex,$(TARGET_CORE_JARS)) HOST_CORE_DEX_LOCATIONS := $(foreach jar,$(HOST_CORE_JARS), $(HOST_OUT_JAVA_LIBRARIES)/$(jar).jar) diff --git a/compiler/image_test.cc b/compiler/image_test.cc index 772cc80146..dd1d74473d 100644 --- a/compiler/image_test.cc +++ b/compiler/image_test.cc @@ -143,7 +143,7 @@ TEST_F(ImageTest, WriteRead) { 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/runtime/Android.mk b/runtime/Android.mk index b38f9bc9a5..41cd3d231d 100644 --- a/runtime/Android.mk +++ b/runtime/Android.mk @@ -141,6 +141,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 10ed0f4dfa..685e771e97 100644 --- a/runtime/asm_support.h +++ b/runtime/asm_support.h @@ -132,16 +132,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 (36 + MIRROR_OBJECT_HEADER_SIZE) +#define MIRROR_CLASS_ACCESS_FLAGS_OFFSET (72 + MIRROR_OBJECT_HEADER_SIZE) ADD_TEST_EQ(MIRROR_CLASS_ACCESS_FLAGS_OFFSET, art::mirror::Class::AccessFlagsOffset().Int32Value()) -#define MIRROR_CLASS_OBJECT_SIZE_OFFSET (112 + MIRROR_OBJECT_HEADER_SIZE) +#define MIRROR_CLASS_OBJECT_SIZE_OFFSET (116 + MIRROR_OBJECT_HEADER_SIZE) ADD_TEST_EQ(MIRROR_CLASS_OBJECT_SIZE_OFFSET, art::mirror::Class::ObjectSizeOffset().Int32Value()) -#define MIRROR_CLASS_STATUS_OFFSET (124 + MIRROR_OBJECT_HEADER_SIZE) +#define MIRROR_CLASS_STATUS_OFFSET (128 + 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 9ca6492fb1..6e7d8e54f1 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -3443,7 +3443,7 @@ ArtMethod* ClassLinker::FindMethodForProxy(mirror::Class* proxy_class, 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 a4e0227a6b..7648a4fadc 100644 --- a/runtime/class_linker_test.cc +++ b/runtime/class_linker_test.cc @@ -488,6 +488,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_loader_), "classLoader"); addOffset(OFFSETOF_MEMBER(mirror::Class, class_size_), "classSize"); addOffset(OFFSETOF_MEMBER(mirror::Class, clinit_thread_id_), "clinitThreadId"); @@ -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"); }; @@ -595,7 +596,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 5f9e413ed2..ff6d07d126 100644 --- a/runtime/common_runtime_test.cc +++ b/runtime/common_runtime_test.cc @@ -302,7 +302,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)); @@ -406,8 +411,8 @@ void CommonRuntimeTest::TearDown() { Runtime::Current()->GetHeap()->VerifyHeap(); // Check for heap corruption after the test } -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 34fdd8d76a..23926fdc91 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/dex_file_test.cc b/runtime/dex_file_test.cc index 90b35a3e04..ef66bd9dcb 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/mirror/class.h b/runtime/mirror/class.h index 0453906171..7af391e09d 100644 --- a/runtime/mirror/class.h +++ b/runtime/mirror/class.h @@ -522,8 +522,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 + 68; + return ComputeClassSize(true, vtable_entries, 0, 0, 3, 1, 0, pointer_size); } // The size of a java.lang.Class representing a primitive such as int.class. @@ -1181,6 +1181,8 @@ class MANAGED Class FINAL : public Object { static MemberOffset EmbeddedImTableOffset(size_t pointer_size); static MemberOffset EmbeddedVTableOffset(size_t pointer_size); + HeapReference<Object> annotation_type_; + // Defining class loader, or null for the "bootstrap" system loader. HeapReference<ClassLoader> class_loader_; @@ -1223,10 +1225,6 @@ class MANAGED Class FINAL : public Object { // virtual_ methods_ for miranda methods. HeapReference<PointerArray> vtable_; - // Access flags; low 16 bits are defined by VM spec. - // Note: Shuffled back. - uint32_t access_flags_; - // static, private, and <init> methods. Pointer to an ArtMethod array. uint64_t direct_methods_; @@ -1246,6 +1244,11 @@ class MANAGED Class FINAL : public Object { // Virtual methods defined in this class; invoked through vtable. Pointer to an ArtMethod array. uint64_t virtual_methods_; + + // Access flags; low 16 bits are defined by VM spec. + // Note: Shuffled back. + uint32_t access_flags_; + // Total size of the Class instance; used when allocating storage on gc heap. // See also object_size_. uint32_t class_size_; 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 d283f58866..e17e379474 100644 --- a/runtime/mirror/string-inl.h +++ b/runtime/mirror/string-inl.h @@ -31,8 +31,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 1c21edbc42..bcedaa095b 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_LOCKS_REQUIRED(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 9cc0b6f5c4..bf686d700b 100644 --- a/runtime/mirror/throwable.h +++ b/runtime/mirror/throwable.h @@ -60,16 +60,16 @@ class MANAGED Throwable : public Object { private: Object* GetStackState() SHARED_LOCKS_REQUIRED(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_LOCKS_REQUIRED(Locks::mutator_lock_) { return GetFieldObjectVolatile<Object>(OFFSET_OF_OBJECT_MEMBER(Throwable, stack_trace_)); } // 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..be4e72001a --- /dev/null +++ b/runtime/native/OpenjdkJvm.cc @@ -0,0 +1,616 @@ +/* + * 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> + +#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 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 void JVM_Exit(jint status) { + LOG(INFO) << "System.exit called, status: " << status; + art::Runtime::Current()->CallExitHook(status); + exit(status); +} + +JNIEXPORT jstring JVM_NativeLoad(JNIEnv* env, jstring javaFilename, jobject javaLoader, + jstring javaLdLibraryPath) { + ScopedUtfChars filename(env, javaFilename); + if (filename.c_str() == NULL) { + return NULL; + } + + if (javaLdLibraryPath != NULL) { + ScopedUtfChars ldLibraryPath(env, javaLdLibraryPath); + if (ldLibraryPath.c_str() == NULL) { + return NULL; + } + void* sym = dlsym(RTLD_DEFAULT, "android_update_LD_LIBRARY_PATH"); + if (sym != NULL) { + typedef void (*Fn)(const char*); + Fn android_update_LD_LIBRARY_PATH = reinterpret_cast<Fn>(sym); + (*android_update_LD_LIBRARY_PATH)(ldLibraryPath.c_str()); + } else { + LOG(ERROR) << "android_update_LD_LIBRARY_PATH not found; .so dependencies will not work!"; + } + } + + std::string detail; + { + 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, &detail); + if (success) { + return nullptr; + } + } + + // Don't let a pending exception from JNI_OnLoad cause a CheckJNI issue with NewStringUTF. + env->ExceptionClear(); + return env->NewStringUTF(detail.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, jclass threadClass) { + sched_yield(); +} + +JNIEXPORT void JVM_Sleep(JNIEnv* env, jclass threadClass, 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) { + 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, 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, jobject javaObject) { + if (UNLIKELY(javaObject == nullptr)) { + return 0; + } + art::ScopedFastNativeObjectAccess soa(env); + art::mirror::Object* o = soa.Decode<art::mirror::Object*>(javaObject); + return static_cast<jint>(o->IdentityHashCode()); +} + +JNIEXPORT jlong JVM_NanoTime(JNIEnv* env, jclass unused) { +#if defined(HAVE_POSIX_CLOCKS) + timespec now; + clock_gettime(CLOCK_MONOTONIC, &now); + return now.tv_sec * 1000000000LL + now.tv_nsec; +#else + timeval now; + gettimeofday(&now, NULL); + return static_cast<jlong>(now.tv_sec) * 1000000000LL + now.tv_usec * 1000LL; +#endif +} +static void ThrowArrayStoreException_NotAnArray(const char* identifier, art::mirror::Object* array) + SHARED_LOCKS_REQUIRED(art::Locks::mutator_lock_) { + std::string actualType(art::PrettyTypeOf(array)); + art::Thread* self = art::Thread::Current(); + self->ThrowNewExceptionF("Ljava/lang/ArrayStoreException;", + "%s of type %s is not an array", identifier, actualType.c_str()); +} + +JNIEXPORT void JVM_ArrayCopy(JNIEnv* env, jclass unused, jobject javaSrc, + jint srcPos, jobject javaDst, jint dstPos, jint length) { + // The API is defined in terms of length, but length is somewhat overloaded so we use count. + const jint count = length; + art::ScopedFastNativeObjectAccess soa(env); + + // Null pointer checks. + if (UNLIKELY(javaSrc == nullptr)) { + art::ThrowNullPointerException("src == null"); + return; + } + if (UNLIKELY(javaDst == nullptr)) { + art::ThrowNullPointerException("dst == null"); + return; + } + + // Make sure source and destination are both arrays. + art::mirror::Object* srcObject = soa.Decode<art::mirror::Object*>(javaSrc); + if (UNLIKELY(!srcObject->IsArrayInstance())) { + ThrowArrayStoreException_NotAnArray("source", srcObject); + return; + } + art::mirror::Object* dstObject = soa.Decode<art::mirror::Object*>(javaDst); + if (UNLIKELY(!dstObject->IsArrayInstance())) { + ThrowArrayStoreException_NotAnArray("destination", dstObject); + return; + } + art::mirror::Array* srcArray = srcObject->AsArray(); + art::mirror::Array* dstArray = dstObject->AsArray(); + + // Bounds checking. + if (UNLIKELY(srcPos < 0) || UNLIKELY(dstPos < 0) || UNLIKELY(count < 0) || + UNLIKELY(srcPos > srcArray->GetLength() - count) || + UNLIKELY(dstPos > dstArray->GetLength() - count)) { + soa.Self()->ThrowNewExceptionF("Ljava/lang/ArrayIndexOutOfBoundsException;", + "src.length=%d srcPos=%d dst.length=%d dstPos=%d length=%d", + srcArray->GetLength(), srcPos, dstArray->GetLength(), dstPos, + count); + return; + } + + art::mirror::Class* dstComponentType = dstArray->GetClass()->GetComponentType(); + art::mirror::Class* srcComponentType = srcArray->GetClass()->GetComponentType(); + art::Primitive::Type dstComponentPrimitiveType = dstComponentType->GetPrimitiveType(); + + if (LIKELY(srcComponentType == dstComponentType)) { + // Trivial assignability. + switch (dstComponentPrimitiveType) { + case art::Primitive::kPrimVoid: + LOG(FATAL) << "Unreachable, cannot have arrays of type void"; + return; + case art::Primitive::kPrimBoolean: + case art::Primitive::kPrimByte: + DCHECK_EQ(art::Primitive::ComponentSize(dstComponentPrimitiveType), 1U); + dstArray->AsByteSizedArray()->Memmove(dstPos, srcArray->AsByteSizedArray(), srcPos, count); + return; + case art::Primitive::kPrimChar: + case art::Primitive::kPrimShort: + DCHECK_EQ(art::Primitive::ComponentSize(dstComponentPrimitiveType), 2U); + dstArray->AsShortSizedArray()->Memmove(dstPos, srcArray->AsShortSizedArray(), srcPos, count); + return; + case art::Primitive::kPrimInt: + case art::Primitive::kPrimFloat: + DCHECK_EQ(art::Primitive::ComponentSize(dstComponentPrimitiveType), 4U); + dstArray->AsIntArray()->Memmove(dstPos, srcArray->AsIntArray(), srcPos, count); + return; + case art::Primitive::kPrimLong: + case art::Primitive::kPrimDouble: + DCHECK_EQ(art::Primitive::ComponentSize(dstComponentPrimitiveType), 8U); + dstArray->AsLongArray()->Memmove(dstPos, srcArray->AsLongArray(), srcPos, count); + return; + case art::Primitive::kPrimNot: { + art::mirror::ObjectArray<art::mirror::Object>* dstObjArray = dstArray->AsObjectArray<art::mirror::Object>(); + art::mirror::ObjectArray<art::mirror::Object>* srcObjArray = srcArray->AsObjectArray<art::mirror::Object>(); + dstObjArray->AssignableMemmove(dstPos, srcObjArray, srcPos, count); + return; + } + default: + LOG(FATAL) << "Unknown array type: " << art::PrettyTypeOf(srcArray); + return; + } + } + // If one of the arrays holds a primitive type the other array must hold the exact same type. + if (UNLIKELY((dstComponentPrimitiveType != art::Primitive::kPrimNot) || + srcComponentType->IsPrimitive())) { + std::string srcType(art::PrettyTypeOf(srcArray)); + std::string dstType(art::PrettyTypeOf(dstArray)); + soa.Self()->ThrowNewExceptionF("Ljava/lang/ArrayStoreException;", + "Incompatible types: src=%s, dst=%s", + srcType.c_str(), dstType.c_str()); + return; + } + // Arrays hold distinct types and so therefore can't alias - use memcpy instead of memmove. + art::mirror::ObjectArray<art::mirror::Object>* dstObjArray = dstArray->AsObjectArray<art::mirror::Object>(); + art::mirror::ObjectArray<art::mirror::Object>* srcObjArray = srcArray->AsObjectArray<art::mirror::Object>(); + // If we're assigning into say Object[] then we don't need per element checks. + if (dstComponentType->IsAssignableFrom(srcComponentType)) { + dstObjArray->AssignableMemcpy(dstPos, srcObjArray, srcPos, count); + return; + } + dstObjArray->AssignableCheckingMemcpy(dstPos, srcObjArray, srcPos, count, true); +} + +JNIEXPORT jint JVM_FindSignal(const char* name) { + LOG(FATAL) << "JVM_FindSignal is not implemented"; + return 0; +} + +JNIEXPORT void* JVM_RegisterSignal(jint signum, void* handler) { + LOG(FATAL) << "JVM_RegisterSignal is not implemented"; + return nullptr; +} + +JNIEXPORT jboolean JVM_RaiseSignal(jint signum) { + LOG(FATAL) << "JVM_RaiseSignal is not implemented"; + return JNI_FALSE; +} + +JNIEXPORT void JVM_Halt(jint code) { + exit(code); +} + +JNIEXPORT jboolean JVM_IsNaN(jdouble d) { + return isnan(d); +} diff --git a/runtime/native/java_lang_System.cc b/runtime/native/java_lang_System.cc index 736b42b739..54472756e3 100644 --- a/runtime/native/java_lang_System.cc +++ b/runtime/native/java_lang_System.cc @@ -28,124 +28,6 @@ namespace art { -/* - * We make guarantees about the atomicity of accesses to primitive variables. These guarantees - * also apply to elements of arrays. In particular, 8-bit, 16-bit, and 32-bit accesses must not - * cause "word tearing". Accesses to 64-bit array elements may be two 32-bit operations. - * References are never torn regardless of the number of bits used to represent them. - */ - -static void ThrowArrayStoreException_NotAnArray(const char* identifier, mirror::Object* array) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { - std::string actualType(PrettyTypeOf(array)); - Thread* self = Thread::Current(); - self->ThrowNewExceptionF("Ljava/lang/ArrayStoreException;", - "%s of type %s is not an array", identifier, actualType.c_str()); -} - -static void System_arraycopy(JNIEnv* env, jclass, jobject javaSrc, jint srcPos, jobject javaDst, - jint dstPos, jint length) { - // The API is defined in terms of length, but length is somewhat overloaded so we use count. - const jint count = length; - ScopedFastNativeObjectAccess soa(env); - - // Null pointer checks. - if (UNLIKELY(javaSrc == nullptr)) { - ThrowNullPointerException("src == null"); - return; - } - if (UNLIKELY(javaDst == nullptr)) { - ThrowNullPointerException("dst == null"); - return; - } - - // Make sure source and destination are both arrays. - mirror::Object* srcObject = soa.Decode<mirror::Object*>(javaSrc); - if (UNLIKELY(!srcObject->IsArrayInstance())) { - ThrowArrayStoreException_NotAnArray("source", srcObject); - return; - } - mirror::Object* dstObject = soa.Decode<mirror::Object*>(javaDst); - if (UNLIKELY(!dstObject->IsArrayInstance())) { - ThrowArrayStoreException_NotAnArray("destination", dstObject); - return; - } - mirror::Array* srcArray = srcObject->AsArray(); - mirror::Array* dstArray = dstObject->AsArray(); - - // Bounds checking. - if (UNLIKELY(srcPos < 0) || UNLIKELY(dstPos < 0) || UNLIKELY(count < 0) || - UNLIKELY(srcPos > srcArray->GetLength() - count) || - UNLIKELY(dstPos > dstArray->GetLength() - count)) { - soa.Self()->ThrowNewExceptionF("Ljava/lang/ArrayIndexOutOfBoundsException;", - "src.length=%d srcPos=%d dst.length=%d dstPos=%d length=%d", - srcArray->GetLength(), srcPos, dstArray->GetLength(), dstPos, - count); - return; - } - - mirror::Class* dstComponentType = dstArray->GetClass()->GetComponentType(); - mirror::Class* srcComponentType = srcArray->GetClass()->GetComponentType(); - Primitive::Type dstComponentPrimitiveType = dstComponentType->GetPrimitiveType(); - - if (LIKELY(srcComponentType == dstComponentType)) { - // Trivial assignability. - switch (dstComponentPrimitiveType) { - case Primitive::kPrimVoid: - LOG(FATAL) << "Unreachable, cannot have arrays of type void"; - UNREACHABLE(); - case Primitive::kPrimBoolean: - case Primitive::kPrimByte: - DCHECK_EQ(Primitive::ComponentSize(dstComponentPrimitiveType), 1U); - dstArray->AsByteSizedArray()->Memmove(dstPos, srcArray->AsByteSizedArray(), srcPos, count); - return; - case Primitive::kPrimChar: - case Primitive::kPrimShort: - DCHECK_EQ(Primitive::ComponentSize(dstComponentPrimitiveType), 2U); - dstArray->AsShortSizedArray()->Memmove(dstPos, srcArray->AsShortSizedArray(), srcPos, count); - return; - case Primitive::kPrimInt: - case Primitive::kPrimFloat: - DCHECK_EQ(Primitive::ComponentSize(dstComponentPrimitiveType), 4U); - dstArray->AsIntArray()->Memmove(dstPos, srcArray->AsIntArray(), srcPos, count); - return; - case Primitive::kPrimLong: - case Primitive::kPrimDouble: - DCHECK_EQ(Primitive::ComponentSize(dstComponentPrimitiveType), 8U); - dstArray->AsLongArray()->Memmove(dstPos, srcArray->AsLongArray(), srcPos, count); - return; - case Primitive::kPrimNot: { - mirror::ObjectArray<mirror::Object>* dstObjArray = dstArray->AsObjectArray<mirror::Object>(); - mirror::ObjectArray<mirror::Object>* srcObjArray = srcArray->AsObjectArray<mirror::Object>(); - dstObjArray->AssignableMemmove(dstPos, srcObjArray, srcPos, count); - return; - } - default: - LOG(FATAL) << "Unknown array type: " << PrettyTypeOf(srcArray); - UNREACHABLE(); - } - } - // If one of the arrays holds a primitive type the other array must hold the exact same type. - if (UNLIKELY((dstComponentPrimitiveType != Primitive::kPrimNot) || - srcComponentType->IsPrimitive())) { - std::string srcType(PrettyTypeOf(srcArray)); - std::string dstType(PrettyTypeOf(dstArray)); - soa.Self()->ThrowNewExceptionF("Ljava/lang/ArrayStoreException;", - "Incompatible types: src=%s, dst=%s", - srcType.c_str(), dstType.c_str()); - return; - } - // Arrays hold distinct types and so therefore can't alias - use memcpy instead of memmove. - mirror::ObjectArray<mirror::Object>* dstObjArray = dstArray->AsObjectArray<mirror::Object>(); - mirror::ObjectArray<mirror::Object>* srcObjArray = srcArray->AsObjectArray<mirror::Object>(); - // If we're assigning into say Object[] then we don't need per element checks. - if (dstComponentType->IsAssignableFrom(srcComponentType)) { - dstObjArray->AssignableMemcpy(dstPos, srcObjArray, srcPos, count); - return; - } - dstObjArray->AssignableCheckingMemcpy(dstPos, srcObjArray, srcPos, count, true); -} - // Template to convert general array to that of its specific primitive type. template <typename T> inline T* AsPrimitiveArray(mirror::Array* array) { @@ -215,17 +97,7 @@ static void System_arraycopyBooleanUnchecked(JNIEnv* env, jclass, jobject javaSr javaDst, dstPos, count); } -static jint System_identityHashCode(JNIEnv* env, jclass, jobject javaObject) { - if (UNLIKELY(javaObject == nullptr)) { - return 0; - } - ScopedFastNativeObjectAccess soa(env); - mirror::Object* o = soa.Decode<mirror::Object*>(javaObject); - return static_cast<jint>(o->IdentityHashCode()); -} - static JNINativeMethod gMethods[] = { - NATIVE_METHOD(System, arraycopy, "!(Ljava/lang/Object;ILjava/lang/Object;II)V"), NATIVE_METHOD(System, arraycopyCharUnchecked, "!([CI[CII)V"), NATIVE_METHOD(System, arraycopyByteUnchecked, "!([BI[BII)V"), NATIVE_METHOD(System, arraycopyShortUnchecked, "!([SI[SII)V"), @@ -234,7 +106,6 @@ static JNINativeMethod gMethods[] = { NATIVE_METHOD(System, arraycopyFloatUnchecked, "!([FI[FII)V"), NATIVE_METHOD(System, arraycopyDoubleUnchecked, "!([DI[DII)V"), NATIVE_METHOD(System, arraycopyBooleanUnchecked, "!([ZI[ZII)V"), - NATIVE_METHOD(System, identityHashCode, "!(Ljava/lang/Object;)I"), }; void register_java_lang_System(JNIEnv* env) { diff --git a/runtime/native/sun_misc_Unsafe.cc b/runtime/native/sun_misc_Unsafe.cc index 770644cef0..4b8e233bd9 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,283 @@ static jint Unsafe_getArrayIndexScaleForComponentType(JNIEnv* env, jclass, jobje return Primitive::ComponentSize(primitive_type); } +static jint Unsafe_addressSize(JNIEnv* env, jobject) { + return sizeof(void*); +} + +static jint Unsafe_pageSize(JNIEnv* env, jobject) { + 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, jobject, jlong address) { + free(reinterpret_cast<void*>(static_cast<uintptr_t>(address))); +} + +static void Unsafe_setMemory(JNIEnv* env, jobject, jlong address, jlong bytes, jbyte value) { + memset(reinterpret_cast<void*>(static_cast<uintptr_t>(address)), value, bytes); +} + +static jbyte Unsafe_getByte$(JNIEnv* env, jobject, jlong address) { + return *reinterpret_cast<jbyte*>(address); +} + +static void Unsafe_putByte$(JNIEnv* env, jobject, jlong address, jbyte value) { + *reinterpret_cast<jbyte*>(address) = value; +} + +static jshort Unsafe_getShort$(JNIEnv* env, jobject, jlong address) { + return *reinterpret_cast<jshort*>(address); +} + +static void Unsafe_putShort$(JNIEnv* env, jobject, jlong address, jshort value) { + *reinterpret_cast<jshort*>(address) = value; +} + +static jchar Unsafe_getChar$(JNIEnv* env, jobject, jlong address) { + return *reinterpret_cast<jchar*>(address); +} + +static void Unsafe_putChar$(JNIEnv* env, jobject, jlong address, jchar value) { + *reinterpret_cast<jchar*>(address) = value; +} + +static jint Unsafe_getInt$(JNIEnv* env, jobject, jlong address) { + return *reinterpret_cast<jint*>(address); +} + +static void Unsafe_putInt$(JNIEnv* env, jobject, jlong address, jint value) { + *reinterpret_cast<jint*>(address) = value; +} + +static jlong Unsafe_getLong$(JNIEnv* env, jobject, jlong address) { + return *reinterpret_cast<jlong*>(address); +} + +static void Unsafe_putLong$(JNIEnv* env, jobject, jlong address, jlong value) { + *reinterpret_cast<jlong*>(address) = value; +} + +static jfloat Unsafe_getFloat$(JNIEnv* env, jobject, jlong address) { + return *reinterpret_cast<jfloat*>(address); +} + +static void Unsafe_putFloat$(JNIEnv* env, jobject, jlong address, jfloat value) { + *reinterpret_cast<jfloat*>(address) = value; +} +static jdouble Unsafe_getDouble$(JNIEnv* env, jobject, jlong address) { + return *reinterpret_cast<jdouble*>(address); +} + +static void Unsafe_putDouble$(JNIEnv* env, jobject, jlong address, jdouble value) { + *reinterpret_cast<jdouble*>(address) = value; +} + +static jlong Unsafe_getAddress(JNIEnv* env ATTRIBUTE_UNUSED, jobject, jlong address) { + void* p = (void*)(uintptr_t)address; + return (uintptr_t)(*(void**)p); +} + +static void Unsafe_copyMemory(JNIEnv *env, jobject unsafe, 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_LOCKS_REQUIRED(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_LOCKS_REQUIRED(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, + 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, + 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 +487,41 @@ 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, getAddress, "!(J)J"), + 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 570c59c037..2798d58a98 100644 --- a/runtime/oat_file_assistant_test.cc +++ b/runtime/oat_file_assistant_test.cc @@ -956,7 +956,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 a8575de425..eee4910182 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 93f66ec30e..d4917a3311 100644 --- a/runtime/runtime.cc +++ b/runtime/runtime.cc @@ -1140,15 +1140,21 @@ void Runtime::InitNativeMethods() { // 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! + // Then set up libjavacore / libflavacore, 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 reason; if (!java_vm_->LoadNativeLibrary(env, "libjavacore.so", nullptr, &reason)) { LOG(FATAL) << "LoadNativeLibrary failed for \"libjavacore.so\": " << reason; } } + { + std::string reason; + if (!java_vm_->LoadNativeLibrary(env, "libxxavacore.so", nullptr, &reason)) { + LOG(FATAL) << "LoadNativeLibrary failed for \"libxxavacore.so\": " << reason; + } + } // Initialize well known classes that may invoke runtime native methods. WellKnownClasses::LateInit(env); diff --git a/runtime/well_known_classes.cc b/runtime/well_known_classes.cc index 0c7cce908c..7e6fc86c15 100644 --- a/runtime/well_known_classes.cc +++ b/runtime/well_known_classes.cc @@ -260,7 +260,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"); org_apache_harmony_dalvik_ddmc_DdmServer_broadcast = CacheMethod(env, org_apache_harmony_dalvik_ddmc_DdmServer, true, "broadcast", "(I)V"); org_apache_harmony_dalvik_ddmc_DdmServer_dispatch = CacheMethod(env, org_apache_harmony_dalvik_ddmc_DdmServer, true, "dispatch", "(I[BII)Lorg/apache/harmony/dalvik/ddmc/Chunk;"); @@ -330,9 +330,9 @@ 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_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;"); @@ -340,13 +340,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/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)); |