summaryrefslogtreecommitdiff
path: root/runtime/native/java_lang_System.cc
diff options
context:
space:
mode:
author Brian Carlstrom <bdc@google.com> 2013-07-12 13:46:57 -0700
committer Brian Carlstrom <bdc@google.com> 2013-07-12 17:49:01 -0700
commit7940e44f4517de5e2634a7e07d58d0fb26160513 (patch)
treeac90242d96229a6942f6e24ab137bc1f8f2e0025 /runtime/native/java_lang_System.cc
parent5cd9e3b122f276f610980cbaf0d2ad6ed4cd9088 (diff)
Create separate Android.mk for main build targets
The runtime, compiler, dex2oat, and oatdump now are in seperate trees to prevent dependency creep. They can now be individually built without rebuilding the rest of the art projects. dalvikvm and jdwpspy were already this way. Builds in the art directory should behave as before, building everything including tests. Change-Id: Ic6b1151e5ed0f823c3dd301afd2b13eb2d8feb81
Diffstat (limited to 'runtime/native/java_lang_System.cc')
-rw-r--r--runtime/native/java_lang_System.cc334
1 files changed, 334 insertions, 0 deletions
diff --git a/runtime/native/java_lang_System.cc b/runtime/native/java_lang_System.cc
new file mode 100644
index 0000000000..2462f2fd8e
--- /dev/null
+++ b/runtime/native/java_lang_System.cc
@@ -0,0 +1,334 @@
+/*
+ * Copyright (C) 2008 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.
+ */
+
+#include "common_throws.h"
+#include "gc/accounting/card_table-inl.h"
+#include "jni_internal.h"
+#include "mirror/array.h"
+#include "mirror/class.h"
+#include "mirror/class-inl.h"
+#include "mirror/object-inl.h"
+#include "mirror/object_array-inl.h"
+#include "scoped_thread_state_change.h"
+
+/*
+ * 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 be atomic and
+ * must not cause "word tearing". Accesses to 64-bit array elements must
+ * either be atomic or treated as two 32-bit operations. References are
+ * always read and written atomically, regardless of the number of bits
+ * used to represent them.
+ *
+ * We can't rely on standard libc functions like memcpy(3) and memmove(3)
+ * in our implementation of System.arraycopy, because they may copy
+ * byte-by-byte (either for the full run or for "unaligned" parts at the
+ * start or end). We need to use functions that guarantee 16-bit or 32-bit
+ * atomicity as appropriate.
+ *
+ * System.arraycopy() is heavily used, so having an efficient implementation
+ * is important. The bionic libc provides a platform-optimized memory move
+ * function that should be used when possible. If it's not available,
+ * the trivial "reference implementation" versions below can be used until
+ * a proper version can be written.
+ *
+ * For these functions, The caller must guarantee that dst/src are aligned
+ * appropriately for the element type, and that n is a multiple of the
+ * element size.
+ */
+
+/*
+ * Works like memmove(), except:
+ * - if all arguments are at least 32-bit aligned, we guarantee that we
+ * will use operations that preserve atomicity of 32-bit values
+ * - if not, we guarantee atomicity of 16-bit values
+ *
+ * If all three arguments are not at least 16-bit aligned, the behavior
+ * of this function is undefined. (We could remove this restriction by
+ * testing for unaligned values and punting to memmove(), but that's
+ * not currently useful.)
+ *
+ * TODO: add loop for 64-bit alignment
+ * TODO: use __builtin_prefetch
+ * TODO: write ARM/MIPS/x86 optimized versions
+ */
+void MemmoveWords(void* dst, const void* src, size_t n) {
+ DCHECK_EQ((((uintptr_t) dst | (uintptr_t) src | n) & 0x01), 0U);
+
+ char* d = reinterpret_cast<char*>(dst);
+ const char* s = reinterpret_cast<const char*>(src);
+ size_t copyCount;
+
+ // If the source and destination pointers are the same, this is
+ // an expensive no-op. Testing for an empty move now allows us
+ // to skip a check later.
+ if (n == 0 || d == s) {
+ return;
+ }
+
+ // Determine if the source and destination buffers will overlap if
+ // we copy data forward (i.e. *dst++ = *src++).
+ //
+ // It's okay if the destination buffer starts before the source and
+ // there is some overlap, because the reader is always ahead of the
+ // writer.
+ if (LIKELY((d < s) || ((size_t)(d - s) >= n))) {
+ // Copy forward. We prefer 32-bit loads and stores even for 16-bit
+ // data, so sort that out.
+ if (((reinterpret_cast<uintptr_t>(d) | reinterpret_cast<uintptr_t>(s)) & 0x03) != 0) {
+ // Not 32-bit aligned. Two possibilities:
+ // (1) Congruent, we can align to 32-bit by copying one 16-bit val
+ // (2) Non-congruent, we can do one of:
+ // a. copy whole buffer as a series of 16-bit values
+ // b. load/store 32 bits, using shifts to ensure alignment
+ // c. just copy the as 32-bit values and assume the CPU
+ // will do a reasonable job
+ //
+ // We're currently using (a), which is suboptimal.
+ if (((reinterpret_cast<uintptr_t>(d) ^ reinterpret_cast<uintptr_t>(s)) & 0x03) != 0) {
+ copyCount = n;
+ } else {
+ copyCount = 2;
+ }
+ n -= copyCount;
+ copyCount /= sizeof(uint16_t);
+
+ while (copyCount--) {
+ *reinterpret_cast<uint16_t*>(d) = *reinterpret_cast<const uint16_t*>(s);
+ d += sizeof(uint16_t);
+ s += sizeof(uint16_t);
+ }
+ }
+
+ // Copy 32-bit aligned words.
+ copyCount = n / sizeof(uint32_t);
+ while (copyCount--) {
+ *reinterpret_cast<uint32_t*>(d) = *reinterpret_cast<const uint32_t*>(s);
+ d += sizeof(uint32_t);
+ s += sizeof(uint32_t);
+ }
+
+ // Check for leftovers. Either we finished exactly, or we have one remaining 16-bit chunk.
+ if ((n & 0x02) != 0) {
+ *(uint16_t*)d = *(uint16_t*)s;
+ }
+ } else {
+ // Copy backward, starting at the end.
+ d += n;
+ s += n;
+
+ if (((reinterpret_cast<uintptr_t>(d) | reinterpret_cast<uintptr_t>(s)) & 0x03) != 0) {
+ // try for 32-bit alignment.
+ if (((reinterpret_cast<uintptr_t>(d) ^ reinterpret_cast<uintptr_t>(s)) & 0x03) != 0) {
+ copyCount = n;
+ } else {
+ copyCount = 2;
+ }
+ n -= copyCount;
+ copyCount /= sizeof(uint16_t);
+
+ while (copyCount--) {
+ d -= sizeof(uint16_t);
+ s -= sizeof(uint16_t);
+ *reinterpret_cast<uint16_t*>(d) = *reinterpret_cast<const uint16_t*>(s);
+ }
+ }
+
+ // Copy 32-bit aligned words.
+ copyCount = n / sizeof(uint32_t);
+ while (copyCount--) {
+ d -= sizeof(uint32_t);
+ s -= sizeof(uint32_t);
+ *reinterpret_cast<uint32_t*>(d) = *reinterpret_cast<const uint32_t*>(s);
+ }
+
+ // Copy leftovers.
+ if ((n & 0x02) != 0) {
+ d -= sizeof(uint16_t);
+ s -= sizeof(uint16_t);
+ *reinterpret_cast<uint16_t*>(d) = *reinterpret_cast<const uint16_t*>(s);
+ }
+ }
+}
+
+#define move16 MemmoveWords
+#define move32 MemmoveWords
+
+namespace art {
+
+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();
+ ThrowLocation throw_location = self->GetCurrentLocationForThrow();
+ self->ThrowNewExceptionF(throw_location, "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) {
+ ScopedObjectAccess soa(env);
+
+ // Null pointer checks.
+ if (UNLIKELY(javaSrc == NULL)) {
+ ThrowNullPointerException(NULL, "src == null");
+ return;
+ }
+ if (UNLIKELY(javaDst == NULL)) {
+ ThrowNullPointerException(NULL, "dst == null");
+ return;
+ }
+
+ // Make sure source and destination are both arrays.
+ mirror::Object* srcObject = soa.Decode<mirror::Object*>(javaSrc);
+ mirror::Object* dstObject = soa.Decode<mirror::Object*>(javaDst);
+ if (UNLIKELY(!srcObject->IsArrayInstance())) {
+ ThrowArrayStoreException_NotAnArray("source", srcObject);
+ return;
+ }
+ if (UNLIKELY(!dstObject->IsArrayInstance())) {
+ ThrowArrayStoreException_NotAnArray("destination", dstObject);
+ return;
+ }
+ mirror::Array* srcArray = srcObject->AsArray();
+ mirror::Array* dstArray = dstObject->AsArray();
+ mirror::Class* srcComponentType = srcArray->GetClass()->GetComponentType();
+ mirror::Class* dstComponentType = dstArray->GetClass()->GetComponentType();
+
+ // Bounds checking.
+ if (UNLIKELY(srcPos < 0 || dstPos < 0 || length < 0 || srcPos > srcArray->GetLength() - length || dstPos > dstArray->GetLength() - length)) {
+ ThrowLocation throw_location = soa.Self()->GetCurrentLocationForThrow();
+ soa.Self()->ThrowNewExceptionF(throw_location, "Ljava/lang/ArrayIndexOutOfBoundsException;",
+ "src.length=%d srcPos=%d dst.length=%d dstPos=%d length=%d",
+ srcArray->GetLength(), srcPos, dstArray->GetLength(), dstPos, length);
+ return;
+ }
+
+ // Handle primitive arrays.
+ if (srcComponentType->IsPrimitive() || dstComponentType->IsPrimitive()) {
+ // If one of the arrays holds a primitive type the other array must hold the exact same type.
+ if (UNLIKELY(srcComponentType != dstComponentType)) {
+ std::string srcType(PrettyTypeOf(srcArray));
+ std::string dstType(PrettyTypeOf(dstArray));
+ ThrowLocation throw_location = soa.Self()->GetCurrentLocationForThrow();
+ soa.Self()->ThrowNewExceptionF(throw_location, "Ljava/lang/ArrayStoreException;",
+ "Incompatible types: src=%s, dst=%s",
+ srcType.c_str(), dstType.c_str());
+ return;
+ }
+
+ size_t width = srcArray->GetClass()->GetComponentSize();
+ uint8_t* dstBytes = reinterpret_cast<uint8_t*>(dstArray->GetRawData(width));
+ const uint8_t* srcBytes = reinterpret_cast<const uint8_t*>(srcArray->GetRawData(width));
+
+ switch (width) {
+ case 1:
+ memmove(dstBytes + dstPos, srcBytes + srcPos, length);
+ break;
+ case 2:
+ move16(dstBytes + dstPos * 2, srcBytes + srcPos * 2, length * 2);
+ break;
+ case 4:
+ move32(dstBytes + dstPos * 4, srcBytes + srcPos * 4, length * 4);
+ break;
+ case 8:
+ // We don't need to guarantee atomicity of the entire 64-bit word.
+ move32(dstBytes + dstPos * 8, srcBytes + srcPos * 8, length * 8);
+ break;
+ default:
+ LOG(FATAL) << "Unknown primitive array type: " << PrettyTypeOf(srcArray);
+ }
+
+ return;
+ }
+
+ // Neither class is primitive. Are the types trivially compatible?
+ const size_t width = sizeof(mirror::Object*);
+ uint8_t* dstBytes = reinterpret_cast<uint8_t*>(dstArray->GetRawData(width));
+ const uint8_t* srcBytes = reinterpret_cast<const uint8_t*>(srcArray->GetRawData(width));
+ if (dstArray == srcArray || dstComponentType->IsAssignableFrom(srcComponentType)) {
+ // Yes. Bulk copy.
+ COMPILE_ASSERT(sizeof(width) == sizeof(uint32_t), move32_assumes_Object_references_are_32_bit);
+ move32(dstBytes + dstPos * width, srcBytes + srcPos * width, length * width);
+ Runtime::Current()->GetHeap()->WriteBarrierArray(dstArray, dstPos, length);
+ return;
+ }
+
+ // The arrays are not trivially compatible. However, we may still be able to copy some or all of
+ // the elements if the source objects are compatible (for example, copying an Object[] to
+ // String[], the Objects being copied might actually be Strings).
+ // We can't do a bulk move because that would introduce a check-use race condition, so we copy
+ // elements one by one.
+
+ // We already dealt with overlapping copies, so we don't need to cope with that case below.
+ CHECK_NE(dstArray, srcArray);
+
+ mirror::Object* const * srcObjects =
+ reinterpret_cast<mirror::Object* const *>(srcBytes + srcPos * width);
+ mirror::Object** dstObjects = reinterpret_cast<mirror::Object**>(dstBytes + dstPos * width);
+ mirror::Class* dstClass = dstArray->GetClass()->GetComponentType();
+
+ // We want to avoid redundant IsAssignableFrom checks where possible, so we cache a class that
+ // we know is assignable to the destination array's component type.
+ mirror::Class* lastAssignableElementClass = dstClass;
+
+ mirror::Object* o = NULL;
+ int i = 0;
+ for (; i < length; ++i) {
+ o = srcObjects[i];
+ if (o != NULL) {
+ mirror::Class* oClass = o->GetClass();
+ if (lastAssignableElementClass == oClass) {
+ dstObjects[i] = o;
+ } else if (dstClass->IsAssignableFrom(oClass)) {
+ lastAssignableElementClass = oClass;
+ dstObjects[i] = o;
+ } else {
+ // Can't put this element into the array.
+ break;
+ }
+ } else {
+ dstObjects[i] = NULL;
+ }
+ }
+
+ Runtime::Current()->GetHeap()->WriteBarrierArray(dstArray, dstPos, length);
+ if (UNLIKELY(i != length)) {
+ std::string actualSrcType(PrettyTypeOf(o));
+ std::string dstType(PrettyTypeOf(dstArray));
+ ThrowLocation throw_location = soa.Self()->GetCurrentLocationForThrow();
+ soa.Self()->ThrowNewExceptionF(throw_location, "Ljava/lang/ArrayStoreException;",
+ "source[%d] of type %s cannot be stored in destination array of type %s",
+ srcPos + i, actualSrcType.c_str(), dstType.c_str());
+ return;
+ }
+}
+
+static jint System_identityHashCode(JNIEnv* env, jclass, jobject javaObject) {
+ ScopedObjectAccess 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, identityHashCode, "(Ljava/lang/Object;)I"),
+};
+
+void register_java_lang_System(JNIEnv* env) {
+ REGISTER_NATIVE_METHODS("java/lang/System");
+}
+
+} // namespace art