summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Narayan Kamath <narayan@google.com> 2015-11-12 11:49:06 +0000
committer Narayan Kamath <narayan@google.com> 2015-11-12 11:52:42 +0000
commitd1ef4362bf799f9f5d50e5edef8433664b503051 (patch)
tree59aaa140925efa790f787d5e1caf6d0cafd6ae15
parente4cf5892c2a244034900d49499c071b255571bba (diff)
parentf32e8327da5dd33abe18662fbca5e584cd047816 (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.mk9
-rw-r--r--build/Android.common_path.mk2
-rw-r--r--compiler/image_test.cc2
-rw-r--r--runtime/Android.mk1
-rw-r--r--runtime/asm_support.h8
-rw-r--r--runtime/class_linker.cc2
-rw-r--r--runtime/class_linker_test.cc7
-rw-r--r--runtime/common_runtime_test.cc11
-rw-r--r--runtime/common_runtime_test.h4
-rw-r--r--runtime/dex_file_test.cc2
-rw-r--r--runtime/mirror/class.h15
-rw-r--r--runtime/mirror/reference-inl.h2
-rw-r--r--runtime/mirror/string-inl.h4
-rw-r--r--runtime/mirror/throwable.cc4
-rw-r--r--runtime/mirror/throwable.h4
-rw-r--r--runtime/native/OpenjdkJvm.cc616
-rw-r--r--runtime/native/java_lang_System.cc129
-rw-r--r--runtime/native/sun_misc_Unsafe.cc318
-rw-r--r--runtime/oat_file_assistant_test.cc2
-rw-r--r--runtime/parsed_options_test.cc24
-rw-r--r--runtime/runtime.cc12
-rw-r--r--runtime/well_known_classes.cc12
-rw-r--r--runtime/zip_archive_test.cc2
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));