Start adding implementations for runtime-provided native methods.
The library can't do everything...
Change-Id: Ib808c00570c7214aeb2ca058b1a66cacbeb372f1
diff --git a/src/check_jni.cc b/src/check_jni.cc
index eb829a0..88f3fec 100644
--- a/src/check_jni.cc
+++ b/src/check_jni.cc
@@ -1196,7 +1196,7 @@
Array* a = Decode<Array*>(ts, java_array);
size_t byte_count = a->GetLength() * a->GetClass()->GetComponentSize();
- void* result = GuardedCopy::create(reinterpret_cast<ByteArray*>(a)->GetData(), byte_count, true);
+ void* result = GuardedCopy::create(a->GetRawData(), byte_count, true);
if (isCopy != NULL) {
*isCopy = JNI_TRUE;
}
@@ -1219,7 +1219,7 @@
if (mode != JNI_ABORT) {
size_t len = GuardedCopy::fromData(dataBuf)->originalLen;
- memcpy(reinterpret_cast<ByteArray*>(a)->GetData(), dataBuf, len);
+ memcpy(a->GetRawData(), dataBuf, len);
}
if (mode != JNI_COMMIT) {
GuardedCopy::destroy(dataBuf);
diff --git a/src/heap.cc b/src/heap.cc
index bffd19d..58588ef 100644
--- a/src/heap.cc
+++ b/src/heap.cc
@@ -251,6 +251,21 @@
return NULL;
}
+int64_t Heap::GetMaxMemory() {
+ UNIMPLEMENTED(WARNING);
+ return 0;
+}
+
+int64_t Heap::GetTotalMemory() {
+ UNIMPLEMENTED(WARNING);
+ return 0;
+}
+
+int64_t Heap::GetFreeMemory() {
+ UNIMPLEMENTED(WARNING);
+ return 0;
+}
+
void Heap::CollectGarbage() {
CollectGarbageInternal();
}
diff --git a/src/heap.h b/src/heap.h
index d4d43e7..72ceffa 100644
--- a/src/heap.h
+++ b/src/heap.h
@@ -44,6 +44,13 @@
// Initiates an explicit garbage collection.
static void CollectGarbage();
+ // Implements java.lang.Runtime.maxMemory.
+ static int64_t GetMaxMemory();
+ // Implements java.lang.Runtime.totalMemory.
+ static int64_t GetTotalMemory();
+ // Implements java.lang.Runtime.freeMemory.
+ static int64_t GetFreeMemory();
+
// Blocks the caller until the garbage collector becomes idle.
static void WaitForConcurrentGcToComplete();
diff --git a/src/java_lang_Object.cc b/src/java_lang_Object.cc
new file mode 100644
index 0000000..41ff8b2
--- /dev/null
+++ b/src/java_lang_Object.cc
@@ -0,0 +1,66 @@
+/*
+ * 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 "jni_internal.h"
+#include "object.h"
+
+#include "JniConstants.h" // Last to avoid problems with LOG redefinition.
+
+namespace art {
+
+namespace {
+
+jclass Object_getClass(JNIEnv* env, jobject javaThis) {
+ // TODO: we can just share the Object::class_ field with Java and use field access instead.
+ Object* o = Decode<Object*>(env, javaThis);
+ return AddLocalReference<jclass>(env, o->GetClass());
+}
+
+jobject Object_internalClone(JNIEnv* env, jobject javaThis) {
+ Object* o = Decode<Object*>(env, javaThis);
+ return AddLocalReference<jobject>(env, o->Clone());
+}
+
+void Object_notify(JNIEnv* env, jobject javaThis) {
+ Object* o = Decode<Object*>(env, javaThis);
+ o->Notify();
+}
+
+void Object_notifyAll(JNIEnv* env, jobject javaThis) {
+ Object* o = Decode<Object*>(env, javaThis);
+ o->NotifyAll();
+}
+
+void Object_wait(JNIEnv* env, jobject javaThis, jlong ms, jint ns) {
+ Object* o = Decode<Object*>(env, javaThis);
+ o->Wait(ms, ns);
+}
+
+JNINativeMethod gMethods[] = {
+ NATIVE_METHOD(Object, getClass, "()Ljava/lang/Class;"),
+ NATIVE_METHOD(Object, internalClone, "(Ljava/lang/Cloneable;)Ljava/lang/Object;"),
+ NATIVE_METHOD(Object, notify, "()V"),
+ NATIVE_METHOD(Object, notifyAll, "()V"),
+ NATIVE_METHOD(Object, wait, "(JI)V"),
+};
+
+} // namespace
+
+void register_java_lang_Object(JNIEnv* env) {
+ jniRegisterNativeMethods(env, "java/lang/Object", gMethods, NELEM(gMethods));
+}
+
+} // namespace art
diff --git a/src/java_lang_Runtime.cc b/src/java_lang_Runtime.cc
new file mode 100644
index 0000000..a2bd399
--- /dev/null
+++ b/src/java_lang_Runtime.cc
@@ -0,0 +1,95 @@
+/*
+ * 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 <unistd.h>
+#include <limits.h>
+
+#include "heap.h"
+#include "jni_internal.h"
+#include "object.h"
+#include "runtime.h"
+
+#include "JniConstants.h" // Last to avoid problems with LOG redefinition.
+#include "ScopedUtfChars.h"
+
+namespace art {
+
+namespace {
+
+void Runtime_gc(JNIEnv*, jclass) {
+ Heap::CollectGarbage();
+}
+
+void Runtime_nativeExit(JNIEnv* env, jclass, jint status, jboolean isExit) {
+ // isExit is true for System.exit and false for System.halt.
+ if (isExit) {
+ Runtime::Current()->CallExitHook(status);
+ }
+ exit(status);
+}
+
+/*
+ * static String nativeLoad(String filename, ClassLoader loader)
+ *
+ * Load the specified full path as a dynamic library filled with
+ * JNI-compatible methods. Returns null on success, or a failure
+ * message on failure.
+ */
+jstring Runtime_nativeLoad(JNIEnv* env, jclass, jstring javaFilename, jobject javaLoader) {
+ ScopedUtfChars filename(env, javaFilename);
+ if (filename.c_str() == NULL) {
+ return NULL;
+ }
+
+ ClassLoader* classLoader = Decode<ClassLoader*>(env, javaLoader);
+ std::string detail;
+ JavaVMExt* vm = Runtime::Current()->GetJavaVM();
+ bool success = vm->LoadNativeLibrary(filename.c_str(), classLoader, detail);
+ if (success) {
+ return NULL;
+ }
+
+ return env->NewStringUTF(detail.c_str());
+}
+
+jlong Runtime_maxMemory(JNIEnv* env, jclass) {
+ return Heap::GetMaxMemory();
+}
+
+jlong Runtime_totalMemory(JNIEnv* env, jclass) {
+ return Heap::GetTotalMemory();
+}
+
+jlong Runtime_freeMemory(JNIEnv* env, jclass) {
+ return Heap::GetFreeMemory();
+}
+
+static JNINativeMethod gMethods[] = {
+ NATIVE_METHOD(Runtime, freeMemory, "()J"),
+ NATIVE_METHOD(Runtime, gc, "()V"),
+ NATIVE_METHOD(Runtime, maxMemory, "()J"),
+ NATIVE_METHOD(Runtime, nativeExit, "(IZ)V"),
+ NATIVE_METHOD(Runtime, nativeLoad, "(Ljava/lang/String;Ljava/lang/ClassLoader;)Ljava/lang/String;"),
+ NATIVE_METHOD(Runtime, totalMemory, "()J"),
+};
+
+} // namespace
+
+void register_java_lang_Runtime(JNIEnv* env) {
+ jniRegisterNativeMethods(env, "java/lang/Runtime", gMethods, NELEM(gMethods));
+}
+
+} // namespace art
diff --git a/src/java_lang_String.cc b/src/java_lang_String.cc
new file mode 100644
index 0000000..9aa5221
--- /dev/null
+++ b/src/java_lang_String.cc
@@ -0,0 +1,169 @@
+/*
+ * 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 "jni_internal.h"
+#include "object.h"
+
+#include "JniConstants.h" // Last to avoid problems with LOG redefinition.
+
+#ifdef HAVE__MEMCMP16
+// "count" is in 16-bit units.
+extern "C" uint32_t __memcmp16(const uint16_t* s0, const uint16_t* s1, size_t count);
+#define MemCmp16 __memcmp16
+#else
+uint32_t MemCmp16(const uint16_t* s0, const uint16_t* s1, size_t count) {
+ for (size_t i = 0; i < count; i++) {
+ if (s0[i] != s1[i]) {
+ return static_cast<int32_t>(s0[i]) - static_cast<int32_t>(s1[i]);
+ }
+ }
+ return 0;
+}
+#endif
+
+namespace art {
+
+namespace {
+
+jint String_compareTo(JNIEnv* env, jobject javaThis, jobject javaRhs) {
+ String* lhs = Decode<String*>(env, javaThis);
+ String* rhs = Decode<String*>(env, javaRhs);
+
+ if (rhs == NULL) {
+ Thread::Current()->ThrowNewException("Ljava/lang/NullPointerException;", "rhs == null");
+ return -1;
+ }
+
+ // Quick test for comparison of a string with itself.
+ if (lhs == rhs) {
+ return 0;
+ }
+
+ // TODO: is this still true?
+ // The annoying part here is that 0x00e9 - 0xffff != 0x00ea,
+ // because the interpreter converts the characters to 32-bit integers
+ // *without* sign extension before it subtracts them (which makes some
+ // sense since "char" is unsigned). So what we get is the result of
+ // 0x000000e9 - 0x0000ffff, which is 0xffff00ea.
+ int lhsCount = lhs->GetLength();
+ int rhsCount = rhs->GetLength();
+ int countDiff = lhsCount - rhsCount;
+ int minCount = (countDiff < 0) ? lhsCount : rhsCount;
+ const uint16_t* lhsChars = lhs->GetCharArray()->GetData() + lhs->GetOffset();
+ const uint16_t* rhsChars = rhs->GetCharArray()->GetData() + rhs->GetOffset();
+ int otherRes = MemCmp16(lhsChars, rhsChars, minCount);
+ if (otherRes != 0) {
+ return otherRes;
+ }
+ return countDiff;
+}
+
+jboolean String_equals(JNIEnv* env, jobject javaThis, jobject javaRhs) {
+ String* lhs = Decode<String*>(env, javaThis);
+ String* rhs = Decode<String*>(env, javaRhs);
+
+ // Quick test for comparison of a string with itself.
+ if (lhs == rhs) {
+ return JNI_TRUE;
+ }
+
+ // if (!(rhs instanceof String)) return false.
+ if (rhs == NULL || lhs->GetClass() != rhs->GetClass()) {
+ return JNI_FALSE;
+ }
+
+ // Quick length check.
+ int lhsCount = lhs->GetLength();
+ int rhsCount = rhs->GetLength();
+ if (lhsCount != rhsCount) {
+ return JNI_FALSE;
+ }
+
+ // You may, at this point, be tempted to pull out the hashCode fields
+ // and compare them. If both fields have been initialized, and they
+ // are not equal, we can return false immediately.
+ //
+ // However, the hashCode field is often not set. If it is set,
+ // there's an excellent chance that the String is being used as a key
+ // in a hashed data structure (e.g. HashMap). That data structure has
+ // already made the comparison and determined that the hashes are equal,
+ // making a check here redundant.
+ //
+ // It's not clear that checking the hashes will be a win in "typical"
+ // use cases. We err on the side of simplicity and ignore them.
+
+ const uint16_t* lhsChars = lhs->GetCharArray()->GetData() + lhs->GetOffset();
+ const uint16_t* rhsChars = rhs->GetCharArray()->GetData() + rhs->GetOffset();
+ return (MemCmp16(lhsChars, rhsChars, lhsCount) == 0) ? JNI_TRUE : JNI_FALSE;
+}
+
+/*
+ * public int indexOf(int c, int start)
+ *
+ * Scan forward through the string for a matching character.
+ * The character must be <= 0xffff; this method does not handle supplementary
+ * characters.
+ *
+ * Determine the index of the first character matching "ch". The string
+ * to search is described by "chars", "offset", and "count".
+ *
+ * The character must be <= 0xffff. Supplementary characters are handled in
+ * Java.
+ *
+ * The "start" parameter must be clamped to [0..count].
+ *
+ * Returns -1 if no match is found.
+ */
+jint String_fastIndexOf(JNIEnv* env, jobject javaThis, jint ch, jint start) {
+ String* s = Decode<String*>(env, javaThis);
+ const uint16_t* chars = s->GetCharArray()->GetData() + s->GetOffset();
+
+ if (start < 0) {
+ start = 0;
+ }
+
+ /* 16-bit loop, slightly better on ARM */
+ const uint16_t* ptr = chars + start;
+ const uint16_t* endPtr = chars + s->GetLength();
+ while (ptr < endPtr) {
+ if (*ptr++ == ch) {
+ return (ptr-1) - chars;
+ }
+ }
+
+ return -1;
+}
+
+jstring String_intern(JNIEnv* env, jobject javaThis) {
+ String* s = Decode<String*>(env, javaThis);
+ String* result = s->Intern();
+ return AddLocalReference<jstring>(env, result);
+}
+
+JNINativeMethod gMethods[] = {
+ NATIVE_METHOD(String, compareTo, "(Ljava/lang/String;)I"),
+ NATIVE_METHOD(String, equals, "(Ljava/lang/Object;)Z"),
+ NATIVE_METHOD(String, fastIndexOf, "(II)I"),
+ NATIVE_METHOD(String, intern, "()Ljava/lang/String;"),
+};
+
+} // namespace
+
+void register_java_lang_String(JNIEnv* env) {
+ jniRegisterNativeMethods(env, "java/lang/String", gMethods, NELEM(gMethods));
+}
+
+} // namespace art
diff --git a/src/java_lang_System.cc b/src/java_lang_System.cc
new file mode 100644
index 0000000..e874987
--- /dev/null
+++ b/src/java_lang_System.cc
@@ -0,0 +1,259 @@
+/*
+ * 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 "jni_internal.h"
+#include "object.h"
+
+#include "JniConstants.h" // Last to avoid problems with LOG redefinition.
+
+/*
+ * 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.
+ */
+#ifdef __BIONIC__
+#define HAVE_MEMMOVE_WORDS
+#endif
+
+#ifdef HAVE_MEMMOVE_WORDS
+extern "C" void _memmove_words(void* dst, const void* src, size_t n);
+#define move16 _memmove_words
+#define move32 _memmove_words
+#else
+static void move16(void* dst, const void* src, size_t n) {
+ DCHECK((((uintptr_t) dst | (uintptr_t) src | n) & 0x01) == 0);
+
+ uint16_t* d = reinterpret_cast<uint16_t*>(dst);
+ const uint16_t* s = reinterpret_cast<const uint16_t*>(src);
+
+ n /= sizeof(uint16_t);
+
+ if (d < s) {
+ // Copy forwards.
+ while (n--) {
+ *d++ = *s++;
+ }
+ } else {
+ // Copy backwards.
+ d += n;
+ s += n;
+ while (n--) {
+ *--d = *--s;
+ }
+ }
+}
+
+static void move32(void* dst, const void* src, size_t n) {
+ DCHECK((((uintptr_t) dst | (uintptr_t) src | n) & 0x03) == 0);
+
+ uint32_t* d = reinterpret_cast<uint32_t*>(dst);
+ const uint32_t* s = reinterpret_cast<const uint32_t*>(src);
+
+ n /= sizeof(uint32_t);
+
+ if (d < s) {
+ // Copy forwards.
+ while (n--) {
+ *d++ = *s++;
+ }
+ } else {
+ // Copy backwards.
+ d += n;
+ s += n;
+ while (n--) {
+ *--d = *--s;
+ }
+ }
+}
+#endif // HAVE_MEMMOVE_WORDS
+
+namespace art {
+
+namespace {
+
+void ThrowArrayStoreException_NotAnArray(const char* identifier, Object* array) {
+ std::string actualType(PrettyType(array));
+ Thread::Current()->ThrowNewException("Ljava/lang/ArrayStoreException;", "%s is not an array: %s", identifier, actualType.c_str());
+}
+
+void System_arraycopy(JNIEnv* env, jclass, jobject javaSrc, jint srcPos, jobject javaDst, jint dstPos, jint length) {
+ Thread* self = Thread::Current();
+
+ // Null pointer checks.
+ if (javaSrc == NULL) {
+ self->ThrowNewException("Ljava/lang/NullPointerException;", "src == null");
+ return;
+ }
+ if (javaDst == NULL) {
+ self->ThrowNewException("Ljava/lang/NullPointerException;", "dst == null");
+ return;
+ }
+
+ // Make sure source and destination are both arrays.
+ Object* srcObject = Decode<Object*>(env, javaSrc);
+ Object* dstObject = Decode<Object*>(env, javaDst);
+ if (!srcObject->IsArrayInstance()) {
+ ThrowArrayStoreException_NotAnArray("src", srcObject);
+ return;
+ }
+ if (!dstObject->IsArrayInstance()) {
+ ThrowArrayStoreException_NotAnArray("dst", dstObject);
+ return;
+ }
+ Array* srcArray = srcObject->AsArray();
+ Array* dstArray = dstObject->AsArray();
+ Class* srcComponentType = srcArray->GetClass()->GetComponentType();
+ Class* dstComponentType = dstArray->GetClass()->GetComponentType();
+
+ // Bounds checking.
+ if (srcPos < 0 || dstPos < 0 || length < 0 || srcPos > srcArray->GetLength() - length || dstPos > dstArray->GetLength() - length) {
+ self->ThrowNewException("Ljava/lang/ArrayIndexOutOfBoundsException;",
+ "src.length=%d srcPos=%d dst.length=%d dstPos=%d length=%d",
+ srcArray->GetLength(), srcPos, dstArray->GetLength(), dstPos, length);
+ return;
+ }
+
+ uint8_t* dstBytes = reinterpret_cast<uint8_t*>(dstArray->GetRawData());
+ const uint8_t* srcBytes = reinterpret_cast<const uint8_t*>(srcArray->GetRawData());
+
+ // 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 (srcComponentType->IsPrimitive() != dstComponentType->IsPrimitive() || srcComponentType != dstComponentType) {
+ std::string srcType(PrettyType(srcArray));
+ std::string dstType(PrettyType(dstArray));
+ self->ThrowNewException("Ljava/lang/ArrayStoreException;",
+ "Incompatible types: src=%s, dst=%s", srcType.c_str(), dstType.c_str());
+ return;
+ }
+
+ switch (srcArray->GetClass()->GetComponentSize()) {
+ 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: " << PrettyType(srcArray);
+ }
+
+ return;
+ }
+
+ // Neither class is primitive. Are the types trivially compatible?
+ const int width = sizeof(Object*);
+ bool sameDimensions = srcArray->GetClass()->array_rank_ == dstArray->GetClass()->array_rank_;
+ if (sameDimensions && srcComponentType->InstanceOf(dstComponentType)) {
+ // Yes. Bulk copy.
+ move32(dstBytes + dstPos * width, srcBytes + srcPos * width, length * width);
+ UNIMPLEMENTED(WARNING) << "write barriers in System.arraycopy";
+ //dvmWriteBarrierArray(dstArray, dstPos, dstPos + length);
+ return;
+ }
+
+ // The arrays are not trivially compatible. However, we
+ // may still be able to do this if the destination object is
+ // compatible (e.g. copy Object[] to String[], but the Object
+ // being copied is actually a String). We need to copy elements
+ // one by one until something goes wrong.
+ //
+ // Because of overlapping moves, what we really want to do
+ // is compare the types and count up how many we can move,
+ // then call move32() to shift the actual data. If we just
+ // start from the front we could do a smear rather than a move.
+
+ // TODO: this idea is flawed. a malicious caller could exploit the check-use
+ // race by modifying the source array after we check but before we copy,
+ // and cause us to copy incompatible elements.
+
+ Object** srcObj = reinterpret_cast<ObjectArray<Object>*>(srcArray)->GetData() + srcPos;
+ Class* dstClass = dstArray->GetClass();
+
+ Class* initialElementClass = NULL;
+ if (length > 0 && srcObj[0] != NULL) {
+ initialElementClass = srcObj[0]->GetClass();
+ if (!Class::CanPutArrayElementNoThrow(initialElementClass, dstClass)) {
+ initialElementClass = NULL;
+ }
+ }
+
+ int copyCount;
+ for (copyCount = 0; copyCount < length; copyCount++) {
+ if (srcObj[copyCount] != NULL && srcObj[copyCount]->GetClass() != initialElementClass && !Class::CanPutArrayElementNoThrow(srcObj[copyCount]->GetClass(), dstClass)) {
+ // Can't put this element into the array.
+ // We'll copy up to this point, then throw.
+ break;
+ }
+ }
+
+ move32(dstBytes + dstPos * width, srcBytes + srcPos * width, copyCount * width);
+ UNIMPLEMENTED(WARNING) << "write barriers in System.arraycopy";
+ //dvmWriteBarrierArray(dstArray, 0, copyCount);
+ if (copyCount != length) {
+ std::string actualSrcType(PrettyType(srcObj[copyCount]));
+ std::string dstType(PrettyType(dstArray));
+ self->ThrowNewException("Ljava/lang/ArrayStoreException;",
+ "source[%d] of type %s cannot be stored in destination array of type %s",
+ srcPos + copyCount, actualSrcType.c_str(), dstType.c_str());
+ return;
+ }
+}
+
+jint System_identityHashCode(JNIEnv* env, jclass, jobject javaObject) {
+ Object* o = Decode<Object*>(env, javaObject);
+ return static_cast<jint>(reinterpret_cast<uintptr_t>(o));
+}
+
+JNINativeMethod gMethods[] = {
+ NATIVE_METHOD(System, arraycopy, "(Ljava/lang/Object;ILjava/lang/Object;II)V"),
+ NATIVE_METHOD(System, identityHashCode, "(Ljava/lang/Object;)I"),
+};
+
+} // namespace
+
+void register_java_lang_System(JNIEnv* env) {
+ jniRegisterNativeMethods(env, "java/lang/System", gMethods, NELEM(gMethods));
+}
+
+} // namespace art
diff --git a/src/java_util_concurrent_atomic_AtomicLong.cc b/src/java_util_concurrent_atomic_AtomicLong.cc
new file mode 100644
index 0000000..eda98ac
--- /dev/null
+++ b/src/java_util_concurrent_atomic_AtomicLong.cc
@@ -0,0 +1,40 @@
+/*
+ * 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 "jni_internal.h"
+#include "object.h"
+
+#include "JniConstants.h" // Last to avoid problems with LOG redefinition.
+
+namespace art {
+
+namespace {
+
+jboolean AtomicLong_VMSupportsCS8(JNIEnv*, jclass) {
+ return JNI_TRUE;
+}
+
+JNINativeMethod gMethods[] = {
+ NATIVE_METHOD(AtomicLong, VMSupportsCS8, "()Z"),
+};
+
+} // namespace
+
+void register_java_util_concurrent_atomic_AtomicLong(JNIEnv* env) {
+ jniRegisterNativeMethods(env, "java/util/concurrent/atomic/AtomicLong", gMethods, NELEM(gMethods));
+}
+
+} // namespace art
diff --git a/src/jni_internal.cc b/src/jni_internal.cc
index 8fb1618..b222b94 100644
--- a/src/jni_internal.cc
+++ b/src/jni_internal.cc
@@ -50,8 +50,6 @@
method->SetInvokeStub(reinterpret_cast<Method::InvokeStub*>(region.pointer()));
}
-namespace {
-
/*
* Add a local reference for an object to the current stack frame. When
* the native function returns, the reference will be discarded.
@@ -65,12 +63,13 @@
* passed in), or NULL on failure.
*/
template<typename T>
-T AddLocalReference(ScopedJniThreadState& ts, Object* obj) {
+T AddLocalReference(JNIEnv* public_env, Object* obj) {
if (obj == NULL) {
return NULL;
}
- IndirectReferenceTable& locals = ts.Env()->locals;
+ JNIEnvExt* env = reinterpret_cast<JNIEnvExt*>(public_env);
+ IndirectReferenceTable& locals = env->locals;
uint32_t cookie = IRT_FIRST_SEGMENT; // TODO
IndirectRef ref = locals.Add(cookie, obj);
@@ -83,7 +82,7 @@
}
#if 0 // TODO: fix this to understand PushLocalFrame, so we can turn it on.
- if (ts.Env()->check_jni) {
+ if (env->check_jni) {
size_t entry_count = locals.Capacity();
if (entry_count > 16) {
std::string class_descriptor(PrettyDescriptor(obj->GetClass()->GetDescriptor()));
@@ -96,7 +95,7 @@
}
#endif
- if (ts.Env()->work_around_app_jni_bugs) {
+ if (env->work_around_app_jni_bugs) {
// Hand out direct pointers to support broken old apps.
return reinterpret_cast<T>(obj);
}
@@ -104,6 +103,20 @@
return reinterpret_cast<T>(ref);
}
+// For external use.
+template<typename T>
+T Decode(JNIEnv* public_env, jobject obj) {
+ JNIEnvExt* env = reinterpret_cast<JNIEnvExt*>(public_env);
+ return reinterpret_cast<T>(env->self->DecodeJObject(obj));
+}
+// Explicit instantiations.
+template Class* Decode<Class*>(JNIEnv*, jobject);
+template ClassLoader* Decode<ClassLoader*>(JNIEnv*, jobject);
+template Object* Decode<Object*>(JNIEnv*, jobject);
+template String* Decode<String*>(JNIEnv*, jobject);
+
+namespace {
+
jweak AddWeakGlobalReference(ScopedJniThreadState& ts, Object* obj) {
if (obj == NULL) {
return NULL;
@@ -115,6 +128,7 @@
return reinterpret_cast<jweak>(ref);
}
+// For internal use.
template<typename T>
T Decode(ScopedJniThreadState& ts, jobject obj) {
return reinterpret_cast<T>(ts.Self()->DecodeJObject(obj));
@@ -364,7 +378,7 @@
JniT NewPrimitiveArray(ScopedJniThreadState& ts, jsize length) {
CHECK_GE(length, 0); // TODO: ReportJniError
ArtT* result = ArtT::Alloc(length);
- return AddLocalReference<JniT>(ts, result);
+ return AddLocalReference<JniT>(ts.Env(), result);
}
template <typename ArrayT, typename CArrayT, typename ArtArrayT>
@@ -634,7 +648,7 @@
// TODO: need to get the appropriate ClassLoader.
const ClassLoader* cl = ts.Self()->GetClassLoaderOverride();
Class* c = class_linker->FindClass(descriptor, cl);
- return AddLocalReference<jclass>(ts, c);
+ return AddLocalReference<jclass>(env, c);
}
static jmethodID FromReflectedMethod(JNIEnv* env, jobject java_method) {
@@ -652,25 +666,25 @@
static jobject ToReflectedMethod(JNIEnv* env, jclass, jmethodID mid, jboolean) {
ScopedJniThreadState ts(env);
Method* method = DecodeMethod(ts, mid);
- return AddLocalReference<jobject>(ts, method);
+ return AddLocalReference<jobject>(env, method);
}
static jobject ToReflectedField(JNIEnv* env, jclass, jfieldID fid, jboolean) {
ScopedJniThreadState ts(env);
Field* field = DecodeField(ts, fid);
- return AddLocalReference<jobject>(ts, field);
+ return AddLocalReference<jobject>(env, field);
}
static jclass GetObjectClass(JNIEnv* env, jobject java_object) {
ScopedJniThreadState ts(env);
Object* o = Decode<Object*>(ts, java_object);
- return AddLocalReference<jclass>(ts, o->GetClass());
+ return AddLocalReference<jclass>(env, o->GetClass());
}
static jclass GetSuperclass(JNIEnv* env, jclass java_class) {
ScopedJniThreadState ts(env);
Class* c = Decode<Class*>(ts, java_class);
- return AddLocalReference<jclass>(ts, c->GetSuperClass());
+ return AddLocalReference<jclass>(env, c->GetSuperClass());
}
static jboolean IsAssignableFrom(JNIEnv* env, jclass java_class1, jclass java_class2) {
@@ -746,7 +760,7 @@
Throwable* original_exception = self->GetException();
self->ClearException();
- ScopedLocalRef<jthrowable> exception(env, AddLocalReference<jthrowable>(ts, original_exception));
+ ScopedLocalRef<jthrowable> exception(env, AddLocalReference<jthrowable>(env, original_exception));
ScopedLocalRef<jclass> exception_class(env, env->GetObjectClass(exception.get()));
jmethodID mid = env->GetMethodID(exception_class.get(), "printStackTrace", "()V");
if (mid == NULL) {
@@ -772,7 +786,7 @@
} else {
// TODO: if adding a local reference failing causes the VM to abort
// then the following check will never occur.
- jthrowable localException = AddLocalReference<jthrowable>(ts, exception);
+ jthrowable localException = AddLocalReference<jthrowable>(env, exception);
if (localException == NULL) {
// We were unable to add a new local reference, and threw a new
// exception. We can't return "exception", because it's not a
@@ -903,7 +917,7 @@
if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(c)) {
return NULL;
}
- return AddLocalReference<jobject>(ts, c->AllocObject());
+ return AddLocalReference<jobject>(env, c->AllocObject());
}
static jobject NewObject(JNIEnv* env, jclass clazz, jmethodID mid, ...) {
@@ -922,7 +936,7 @@
return NULL;
}
Object* result = c->AllocObject();
- jobject local_result = AddLocalReference<jobject>(ts, result);
+ jobject local_result = AddLocalReference<jobject>(env, result);
CallNonvirtualVoidMethodV(env, local_result, java_class, mid, args);
return local_result;
}
@@ -934,7 +948,7 @@
return NULL;
}
Object* result = c->AllocObject();
- jobject local_result = AddLocalReference<jobjectArray>(ts, result);
+ jobject local_result = AddLocalReference<jobjectArray>(env, result);
CallNonvirtualVoidMethodA(env, local_result, java_class, mid, args);
return local_result;
}
@@ -955,19 +969,19 @@
va_start(ap, mid);
JValue result = InvokeVirtualOrInterfaceWithVarArgs(ts, obj, mid, ap);
va_end(ap);
- return AddLocalReference<jobject>(ts, result.l);
+ return AddLocalReference<jobject>(env, result.l);
}
static jobject CallObjectMethodV(JNIEnv* env, jobject obj, jmethodID mid, va_list args) {
ScopedJniThreadState ts(env);
JValue result = InvokeVirtualOrInterfaceWithVarArgs(ts, obj, mid, args);
- return AddLocalReference<jobject>(ts, result.l);
+ return AddLocalReference<jobject>(env, result.l);
}
static jobject CallObjectMethodA(JNIEnv* env, jobject obj, jmethodID mid, jvalue* args) {
ScopedJniThreadState ts(env);
JValue result = InvokeVirtualOrInterfaceWithJValues(ts, obj, mid, args);
- return AddLocalReference<jobject>(ts, result.l);
+ return AddLocalReference<jobject>(env, result.l);
}
static jboolean CallBooleanMethod(JNIEnv* env, jobject obj, jmethodID mid, ...) {
@@ -1146,7 +1160,7 @@
va_list ap;
va_start(ap, mid);
JValue result = InvokeWithVarArgs(ts, obj, mid, ap);
- jobject local_result = AddLocalReference<jobject>(ts, result.l);
+ jobject local_result = AddLocalReference<jobject>(env, result.l);
va_end(ap);
return local_result;
}
@@ -1155,14 +1169,14 @@
jobject obj, jclass clazz, jmethodID mid, va_list args) {
ScopedJniThreadState ts(env);
JValue result = InvokeWithVarArgs(ts, obj, mid, args);
- return AddLocalReference<jobject>(ts, result.l);
+ return AddLocalReference<jobject>(env, result.l);
}
static jobject CallNonvirtualObjectMethodA(JNIEnv* env,
jobject obj, jclass clazz, jmethodID mid, jvalue* args) {
ScopedJniThreadState ts(env);
JValue result = InvokeWithJValues(ts, obj, mid, args);
- return AddLocalReference<jobject>(ts, result.l);
+ return AddLocalReference<jobject>(env, result.l);
}
static jboolean CallNonvirtualBooleanMethod(JNIEnv* env,
@@ -1379,13 +1393,13 @@
ScopedJniThreadState ts(env);
Object* o = Decode<Object*>(ts, obj);
Field* f = DecodeField(ts, fid);
- return AddLocalReference<jobject>(ts, f->GetObject(o));
+ return AddLocalReference<jobject>(env, f->GetObject(o));
}
static jobject GetStaticObjectField(JNIEnv* env, jclass, jfieldID fid) {
ScopedJniThreadState ts(env);
Field* f = DecodeField(ts, fid);
- return AddLocalReference<jobject>(ts, f->GetObject(NULL));
+ return AddLocalReference<jobject>(env, f->GetObject(NULL));
}
static void SetObjectField(JNIEnv* env, jobject java_object, jfieldID fid, jobject java_value) {
@@ -1549,7 +1563,7 @@
va_list ap;
va_start(ap, mid);
JValue result = InvokeWithVarArgs(ts, NULL, mid, ap);
- jobject local_result = AddLocalReference<jobject>(ts, result.l);
+ jobject local_result = AddLocalReference<jobject>(env, result.l);
va_end(ap);
return local_result;
}
@@ -1558,14 +1572,14 @@
jclass clazz, jmethodID mid, va_list args) {
ScopedJniThreadState ts(env);
JValue result = InvokeWithVarArgs(ts, NULL, mid, args);
- return AddLocalReference<jobject>(ts, result.l);
+ return AddLocalReference<jobject>(env, result.l);
}
static jobject CallStaticObjectMethodA(JNIEnv* env,
jclass clazz, jmethodID mid, jvalue* args) {
ScopedJniThreadState ts(env);
JValue result = InvokeWithJValues(ts, NULL, mid, args);
- return AddLocalReference<jobject>(ts, result.l);
+ return AddLocalReference<jobject>(env, result.l);
}
static jboolean CallStaticBooleanMethod(JNIEnv* env,
@@ -1763,7 +1777,7 @@
return NULL;
}
String* result = String::AllocFromUtf16(char_count, chars);
- return AddLocalReference<jstring>(ts, result);
+ return AddLocalReference<jstring>(env, result);
}
static jstring NewStringUTF(JNIEnv* env, const char* utf) {
@@ -1772,7 +1786,7 @@
return NULL;
}
String* result = String::AllocFromModifiedUtf8(utf);
- return AddLocalReference<jstring>(ts, result);
+ return AddLocalReference<jstring>(env, result);
}
static jsize GetStringLength(JNIEnv* env, jstring java_string) {
@@ -1870,7 +1884,7 @@
static jobject GetObjectArrayElement(JNIEnv* env, jobjectArray java_array, jsize index) {
ScopedJniThreadState ts(env);
ObjectArray<Object>* array = Decode<ObjectArray<Object>*>(ts, java_array);
- return AddLocalReference<jobject>(ts, array->Get(index));
+ return AddLocalReference<jobject>(env, array->Get(index));
}
static void SetObjectArrayElement(JNIEnv* env,
@@ -1941,7 +1955,7 @@
result->Set(i, initial_object);
}
}
- return AddLocalReference<jobjectArray>(ts, result);
+ return AddLocalReference<jobjectArray>(env, result);
}
static jshortArray NewShortArray(JNIEnv* env, jsize length) {
diff --git a/src/jni_internal.h b/src/jni_internal.h
index 05df3e4..63be779 100644
--- a/src/jni_internal.h
+++ b/src/jni_internal.h
@@ -22,6 +22,9 @@
void JniAbort(const char* jni_function_name);
+template<typename T> T Decode(JNIEnv*, jobject);
+template<typename T> T AddLocalReference(JNIEnv*, Object*);
+
struct JavaVMExt : public JavaVM {
JavaVMExt(Runtime* runtime, bool check_jni, bool verbose_jni);
~JavaVMExt();
diff --git a/src/object.cc b/src/object.cc
index e0544df..6bc3021 100644
--- a/src/object.cc
+++ b/src/object.cc
@@ -62,6 +62,11 @@
return Heap::AllocObject(this, this->object_size_);
}
+bool Class::CanPutArrayElementNoThrow(const Class* elementClass, const Class* arrayClass) {
+ UNIMPLEMENTED(FATAL);
+ return false;
+}
+
bool Class::Implements(const Class* klass) const {
DCHECK(klass != NULL);
DCHECK(klass->IsInterface());
diff --git a/src/object.h b/src/object.h
index 1db3e83..506e39c 100644
--- a/src/object.h
+++ b/src/object.h
@@ -184,6 +184,11 @@
size_t SizeOf() const;
+ Object* Clone() {
+ UNIMPLEMENTED(FATAL);
+ return NULL;
+ }
+
void MonitorEnter() {
monitor_->Enter();
}
@@ -826,6 +831,10 @@
return MemberOffset(OFFSETOF_MEMBER(Array, first_element_));
}
+ void* GetRawData() {
+ return reinterpret_cast<void*>(first_element_);
+ }
+
protected:
bool IsValidIndex(int32_t index) const {
if (index < 0 || index >= length_) {
@@ -1114,6 +1123,8 @@
return that->IsPublic() || this->IsInSamePackage(that);
}
+ static bool CanPutArrayElementNoThrow(const Class* elementClass, const Class* arrayClass);
+
// Returns the number of static, private, and constructor methods.
size_t NumDirectMethods() const {
return (direct_methods_ != NULL) ? direct_methods_->GetLength() : 0;
@@ -1688,6 +1699,11 @@
return result;
}
+ String* Intern() const {
+ UNIMPLEMENTED(FATAL);
+ return NULL;
+ }
+
private:
// Field order required by test "ValidateFieldOrderOfJavaCppUnionClasses".
CharArray* array_;
diff --git a/src/runtime.cc b/src/runtime.cc
index b126ad9..01abc44 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -63,6 +63,14 @@
// notreached
}
+void Runtime::CallExitHook(jint status) {
+ if (exit_ != NULL) {
+ ScopedThreadStateChange tsc(Thread::Current(), Thread::kNative);
+ exit_(status);
+ LOG(WARNING) << "Exit hook returned instead of exiting!";
+ }
+}
+
// Parse a string of the form /[0-9]+[kKmMgG]?/, which is used to specify
// memory sizes. [kK] indicates kilobytes, [mM] megabytes, and
// [gG] gigabytes.
@@ -356,10 +364,10 @@
//REGISTER(register_dalvik_system_VMStack);
//REGISTER(register_dalvik_system_Zygote);
//REGISTER(register_java_lang_Class);
- //REGISTER(register_java_lang_Object);
- //REGISTER(register_java_lang_Runtime);
- //REGISTER(register_java_lang_String);
- //REGISTER(register_java_lang_System_); // The _ avoids collision with libcore.
+ REGISTER(register_java_lang_Object);
+ REGISTER(register_java_lang_Runtime);
+ REGISTER(register_java_lang_String);
+ REGISTER(register_java_lang_System);
//REGISTER(register_java_lang_Thread);
//REGISTER(register_java_lang_Throwable);
//REGISTER(register_java_lang_VMClassLoader);
@@ -369,7 +377,7 @@
//REGISTER(register_java_lang_reflect_Field);
//REGISTER(register_java_lang_reflect_Method);
//REGISTER(register_java_lang_reflect_Proxy);
- //REGISTER(register_java_util_concurrent_atomic_AtomicLong);
+ REGISTER(register_java_util_concurrent_atomic_AtomicLong);
//REGISTER(register_org_apache_harmony_dalvik_ddmc_DdmServer);
//REGISTER(register_org_apache_harmony_dalvik_ddmc_DdmVmInternal);
//REGISTER(register_sun_misc_Unsafe);
diff --git a/src/runtime.h b/src/runtime.h
index 198bfeb..2717843 100644
--- a/src/runtime.h
+++ b/src/runtime.h
@@ -75,6 +75,8 @@
// Attaches the current native thread to the runtime.
bool AttachCurrentThread(const char* name, JNIEnv** jni_env, bool as_daemon);
+ void CallExitHook(jint status);
+
// Detaches the current native thread from the runtime.
bool DetachCurrentThread();
diff --git a/src/thread.cc b/src/thread.cc
index 062550d..8ec3d74 100644
--- a/src/thread.cc
+++ b/src/thread.cc
@@ -71,21 +71,17 @@
pSet64Static = Field::Set64StaticFromCode;
pGetObjStatic = Field::GetObjStaticFromCode;
pSetObjStatic = Field::SetObjStaticFromCode;
+ pArtCanPutArrayElementNoThrow = Class::CanPutArrayElementNoThrow;
#if 0
-bool (Thread::*pArtUnlockObject)(struct Thread*, struct Object*);
-bool (Thread::*pArtCanPutArrayElementNoThrow)(const struct ClassObject*,
- const struct ClassObject*);
-int (Thread::*pArtInstanceofNonTrivialNoThrow)
- (const struct ClassObject*, const struct ClassObject*);
-int (Thread::*pArtInstanceofNonTrivial) (const struct ClassObject*,
- const struct ClassObject*);
-struct Method* (Thread::*pArtFindInterfaceMethodInCache)(ClassObject*, uint32_t,
- const struct Method*, struct DvmDex*);
-bool (Thread::*pArtUnlockObjectNoThrow)(struct Thread*, struct Object*);
-void (Thread::*pArtLockObjectNoThrow)(struct Thread*, struct Object*);
-struct Object* (Thread::*pArtAllocObjectNoThrow)(struct ClassObject*, int);
-void (Thread::*pArtThrowException)(struct Thread*, struct Object*);
-bool (Thread::*pArtHandleFillArrayDataNoThrow)(struct ArrayObject*, const uint16_t*);
+bool (Thread::*pArtUnlockObject)(Thread*, Object*);
+int (Thread::*pArtInstanceofNonTrivialNoThrow)(const Class*, const Class*);
+int (Thread::*pArtInstanceofNonTrivial) (const Class*, const Class*);
+Method* (Thread::*pArtFindInterfaceMethodInCache)(Class*, uint32_t, const Method*, DvmDex*);
+bool (Thread::*pArtUnlockObjectNoThrow)(Thread*, Object*);
+void (Thread::*pArtLockObjectNoThrow)(Thread*, Object*);
+Object* (Thread::*pArtAllocObjectNoThrow)(Class*, int);
+void (Thread::*pArtThrowException)(Thread*, Object*);
+bool (Thread::*pArtHandleFillArrayDataNoThrow)(Array*, const uint16_t*);
#endif
}
diff --git a/src/thread.h b/src/thread.h
index 86e78b7..4f2d8c8 100644
--- a/src/thread.h
+++ b/src/thread.h
@@ -208,18 +208,15 @@
void (*pSet64Static)(uint32_t, const Method*, uint64_t);
Object* (*pGetObjStatic)(uint32_t, const Method*);
void (*pSetObjStatic)(uint32_t, const Method*, Object*);
- bool (*pArtUnlockObject)(struct Thread*, struct Object*);
- bool (*pArtCanPutArrayElementNoThrow)(const struct ClassObject*,
- const struct ClassObject*);
- int (*pArtInstanceofNonTrivialNoThrow) (const struct ClassObject*,
- const struct ClassObject*);
- int (*pArtInstanceofNonTrivial) (const struct ClassObject*, const struct ClassObject*);
- struct Method* (*pArtFindInterfaceMethodInCache)(ClassObject*, uint32_t,
- const struct Method*, struct DvmDex*);
- bool (*pArtUnlockObjectNoThrow)(struct Thread*, struct Object*);
- void (*pArtLockObjectNoThrow)(struct Thread*, struct Object*);
- struct Object* (*pArtAllocObjectNoThrow)(struct ClassObject*, int);
- void (*pArtThrowException)(struct Thread*, struct Object*);
+ bool (*pArtUnlockObject)(Thread*, Object*);
+ bool (*pArtCanPutArrayElementNoThrow)(const Class*, const Class*);
+ int (*pArtInstanceofNonTrivialNoThrow) (const Class*, const Class*);
+ int (*pArtInstanceofNonTrivial) (const Class*, const Class*);
+ Method* (*pArtFindInterfaceMethodInCache)(Class*, uint32_t, const Method*, struct DvmDex*);
+ bool (*pArtUnlockObjectNoThrow)(Thread*, Object*);
+ void (*pArtLockObjectNoThrow)(Thread*, Object*);
+ Object* (*pArtAllocObjectNoThrow)(Class*, int);
+ void (*pArtThrowException)(Thread*, Object*);
void (*pArtHandleFillArrayDataNoThrow)(Array*, const uint16_t*);
class StackVisitor {