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 {