Refactor runtime support.

Change-Id: Id7470a4105838150d5ceb73ab2c8c83e739660df
diff --git a/src/runtime_support.h b/src/runtime_support.h
index 35f88b5..909fb41 100644
--- a/src/runtime_support.h
+++ b/src/runtime_support.h
@@ -1,180 +1,195 @@
-/*
- * Copyright (C) 2011 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.
- */
+// Copyright 2012 Google Inc. All Rights Reserved.
 
 #ifndef ART_SRC_RUNTIME_SUPPORT_H_
 #define ART_SRC_RUNTIME_SUPPORT_H_
 
 #include "class_linker.h"
+#include "dex_file.h"
+#include "dex_verifier.h"
 #include "object.h"
-#include "thread_list.h"
-#include "utils.h"
+#include "object_utils.h"
+#include "thread.h"
+
+extern "C" void art_proxy_invoke_handler();
+extern "C" void art_work_around_app_jni_bugs();
 
 namespace art {
 
-extern void CheckSuspendFromCode(Thread* thread);
+class Array;
+class Class;
+class Field;
+class Method;
+class Object;
+
+// Helpers to give consistent descriptive exception messages
+void ThrowNewIllegalAccessErrorClass(Thread* self, Class* referrer, Class* accessed);
+void ThrowNewIllegalAccessErrorClassForMethodDispatch(Thread* self, Class* referrer,
+                                                      Class* accessed,
+                                                      const Method* caller,
+                                                      const Method* called,
+                                                      InvokeType type);
+void ThrowNewIncompatibleClassChangeErrorClassForInterfaceDispatch(Thread* self,
+                                                                   const Method* referrer,
+                                                                   const Method* interface_method,
+                                                                   Object* this_object);
+void ThrowNewIllegalAccessErrorField(Thread* self, Class* referrer, Field* accessed);
+void ThrowNewIllegalAccessErrorFinalField(Thread* self, const Method* referrer, Field* accessed);
+
+void ThrowNewIllegalAccessErrorMethod(Thread* self, Class* referrer, Method* accessed);
+void ThrowNullPointerExceptionForFieldAccess(Thread* self, Field* field, bool is_read);
+void ThrowNullPointerExceptionForMethodAccess(Thread* self, Method* caller, uint32_t method_idx,
+                                              InvokeType type);
+
+std::string FieldNameFromIndex(const Method* method, uint32_t ref,
+                               verifier::VerifyErrorRefType ref_type, bool access);
+std::string MethodNameFromIndex(const Method* method, uint32_t ref,
+                                verifier::VerifyErrorRefType ref_type, bool access);
+
+// Given the context of a calling Method, use its DexCache to resolve a type to a Class. If it
+// cannot be resolved, throw an error. If it can, use it to create an instance.
+// When verification/compiler hasn't been able to verify access, optionally perform an access
+// check.
+static inline Object* AllocObjectFromCode(uint32_t type_idx, Method* method, Thread* self,
+                                          bool access_check) {
+  Class* klass = method->GetDexCacheResolvedTypes()->Get(type_idx);
+  Runtime* runtime = Runtime::Current();
+  if (UNLIKELY(klass == NULL)) {
+    klass = runtime->GetClassLinker()->ResolveType(type_idx, method);
+    if (klass == NULL) {
+      DCHECK(self->IsExceptionPending());
+      return NULL;  // Failure
+    }
+  }
+  if (access_check) {
+    if (UNLIKELY(!klass->IsInstantiable())) {
+      self->ThrowNewException("Ljava/lang/InstantiationError;",
+                              PrettyDescriptor(klass).c_str());
+      return NULL;  // Failure
+    }
+    Class* referrer = method->GetDeclaringClass();
+    if (UNLIKELY(!referrer->CanAccess(klass))) {
+      ThrowNewIllegalAccessErrorClass(self, referrer, klass);
+      return NULL;  // Failure
+    }
+  }
+  if (!runtime->GetClassLinker()->EnsureInitialized(klass, true)) {
+    DCHECK(self->IsExceptionPending());
+    return NULL;  // Failure
+  }
+  return klass->AllocObject();
+}
+
+// Given the context of a calling Method, use its DexCache to resolve a type to an array Class. If
+// it cannot be resolved, throw an error. If it can, use it to create an array.
+// When verification/compiler hasn't been able to verify access, optionally perform an access
+// check.
+static inline Array* AllocArrayFromCode(uint32_t type_idx, Method* method, int32_t component_count,
+                                        Thread* self, bool access_check) {
+  if (UNLIKELY(component_count < 0)) {
+    Thread::Current()->ThrowNewExceptionF("Ljava/lang/NegativeArraySizeException;", "%d",
+                                          component_count);
+    return NULL;  // Failure
+  }
+  Class* klass = method->GetDexCacheResolvedTypes()->Get(type_idx);
+  if (UNLIKELY(klass == NULL)) {  // Not in dex cache so try to resolve
+    klass = Runtime::Current()->GetClassLinker()->ResolveType(type_idx, method);
+    if (klass == NULL) {  // Error
+      DCHECK(Thread::Current()->IsExceptionPending());
+      return NULL;  // Failure
+    }
+    CHECK(klass->IsArrayClass()) << PrettyClass(klass);
+  }
+  if (access_check) {
+    Class* referrer = method->GetDeclaringClass();
+    if (UNLIKELY(!referrer->CanAccess(klass))) {
+      ThrowNewIllegalAccessErrorClass(self, referrer, klass);
+      return NULL;  // Failure
+    }
+  }
+  return Array::Alloc(klass, component_count);
+}
+
 extern Array* CheckAndAllocArrayFromCode(uint32_t type_idx, Method* method, int32_t component_count,
                                          Thread* self, bool access_check);
-extern void DebugMe(Method* method, uint32_t info);
-extern void UpdateDebuggerFromCode(Method* method, Thread* thread , int32_t dex_pc, Method** sp);
-extern Object* DecodeJObjectInThread(Thread* thread, jobject obj);
+
 extern Field* FindFieldFromCode(uint32_t field_idx, const Method* referrer, Thread* self,
-                                bool is_static, bool is_primitive, bool is_set, size_t expected_size);
-extern void* FindNativeMethod(Thread* thread);
-extern void ThrowAbstractMethodErrorFromCode(Method* method, Thread* thread, Method** sp);
-const void* UnresolvedDirectMethodTrampolineFromCode(Method*, Method**, Thread*,
-                                                     Runtime::TrampolineType);
+                                bool is_static, bool is_primitive, bool is_set,
+                                size_t expected_size);
+
+// Fast path field resolution that can't throw exceptions
+static inline Field* FindFieldFast(uint32_t field_idx, const Method* referrer, bool is_primitive,
+                                   size_t expected_size, bool is_set) {
+  Field* resolved_field = referrer->GetDeclaringClass()->GetDexCache()->GetResolvedField(field_idx);
+  if (UNLIKELY(resolved_field == NULL)) {
+    return NULL;
+  }
+  Class* fields_class = resolved_field->GetDeclaringClass();
+  // Check class is initiliazed or initializing
+  if (UNLIKELY(!fields_class->IsInitializing())) {
+    return NULL;
+  }
+  Class* referring_class = referrer->GetDeclaringClass();
+  if (UNLIKELY(!referring_class->CanAccess(fields_class) ||
+               !referring_class->CanAccessMember(fields_class,
+                                                 resolved_field->GetAccessFlags()) ||
+               (is_set && resolved_field->IsFinal() && (fields_class != referring_class)))) {
+    // illegal access
+    return NULL;
+  }
+  FieldHelper fh(resolved_field);
+  if (UNLIKELY(fh.IsPrimitiveType() != is_primitive ||
+               fh.FieldSize() != expected_size)) {
+    return NULL;
+  }
+  return resolved_field;
+}
+
+// Fast path method resolution that can't throw exceptions
+static inline Method* FindMethodFast(uint32_t method_idx, Object* this_object, const Method* referrer,
+                              bool access_check, InvokeType type) {
+  bool is_direct = type == kStatic || type == kDirect;
+  if (UNLIKELY(this_object == NULL && !is_direct)) {
+    return NULL;
+  }
+  Method* resolved_method =
+      referrer->GetDeclaringClass()->GetDexCache()->GetResolvedMethod(method_idx);
+  if (UNLIKELY(resolved_method == NULL)) {
+    return NULL;
+  }
+  if (access_check) {
+    Class* methods_class = resolved_method->GetDeclaringClass();
+    Class* referring_class = referrer->GetDeclaringClass();
+    if (UNLIKELY(!referring_class->CanAccess(methods_class) ||
+                 !referring_class->CanAccessMember(methods_class,
+                                                   resolved_method->GetAccessFlags()))) {
+      // potential illegal access
+      return NULL;
+    }
+  }
+  if (type == kInterface) {  // Most common form of slow path dispatch.
+    return this_object->GetClass()->FindVirtualMethodForInterface(resolved_method);
+  } else if (is_direct) {
+    return resolved_method;
+  } else if (type == kSuper) {
+    return referrer->GetDeclaringClass()->GetSuperClass()->GetVTable()->
+        Get(resolved_method->GetMethodIndex());
+  } else {
+    DCHECK(type == kVirtual);
+    return this_object->GetClass()->GetVTable()->Get(resolved_method->GetMethodIndex());
+  }
+}
+
+extern Method* FindMethodFromCode(uint32_t method_idx, Object* this_object, const Method* referrer,
+                                  Thread* self, bool access_check, InvokeType type);
+
 extern Class* ResolveVerifyAndClinit(uint32_t type_idx, const Method* referrer, Thread* self,
                                      bool can_run_clinit, bool verify_access);
-extern Class* InitializeTypeFromCode(uint32_t type_idx, Method* method);
-uint32_t IsAssignableFromCode(const Class* klass, const Class* ref_class);
-void ObjectInitFromCode(Object* o);
-extern void LockObjectFromCode(Thread* thread, Object* obj);
-uint32_t TraceMethodUnwindFromCode(Thread* self);
-extern int32_t CmpgDouble(double a, double b);
-extern int32_t CmplDouble(double a, double b);
-extern int32_t CmpgFloat(float a, float b);
-extern int32_t CmplFloat(float a, float b);
-extern int64_t D2L(double d);
-extern int64_t F2L(float f);
+
+static inline String* ResolveStringFromCode(const Method* referrer, uint32_t string_idx) {
+  ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+  return class_linker->ResolveString(string_idx, referrer);
+}
 
 }  // namespace art
 
-// Helpers for both compiled code and libart.
-extern "C" void art_deliver_exception_from_code(void*);
-extern "C" void art_proxy_invoke_handler();
-extern "C" void art_update_debugger(void*, void*, int32_t, void*);
-
-#if defined(__arm__)
-  /* Compiler helpers */
-  extern "C" int32_t __memcmp16(void*, void*, int32_t);
-  extern "C" int32_t art_indexof(void*, uint32_t, uint32_t, uint32_t);
-  extern "C" int32_t art_string_compareto(void*, void*);
-  extern "C" int32_t art_get32_static_from_code(uint32_t);
-  extern "C" int64_t art_get64_static_from_code(uint32_t);
-  extern "C" void* art_get_obj_static_from_code(uint32_t);
-  extern "C" int32_t art_get32_instance_from_code(uint32_t, void*);
-  extern "C" int64_t art_get64_instance_from_code(uint32_t, void*);
-  extern "C" void* art_get_obj_instance_from_code(uint32_t, void*);
-  extern "C" int art_set32_static_from_code(uint32_t, int32_t);
-  extern "C" int art_set64_static_from_code(uint32_t, int64_t);
-  extern "C" int art_set_obj_static_from_code(uint32_t, void*);
-  extern "C" int art_set32_instance_from_code(uint32_t, void*, int32_t);
-  extern "C" int art_set64_instance_from_code(uint32_t, void*, int64_t);
-  extern "C" int art_set_obj_instance_from_code(uint32_t, void*, void*);
-  extern "C" void art_can_put_array_element_from_code(void*, void*);
-  extern "C" void art_check_cast_from_code(void*, void*);
-  extern "C" void art_do_long_jump(uint32_t*, uint32_t*);
-  extern "C" void art_handle_fill_data_from_code(void*, void*);
-  extern "C" void art_invoke_direct_trampoline_with_access_check(uint32_t, void*);
-  extern "C" void art_invoke_interface_trampoline(uint32_t, void*);
-  extern "C" void art_invoke_interface_trampoline_with_access_check(uint32_t, void*);
-  extern "C" void art_invoke_static_trampoline_with_access_check(uint32_t, void*);
-  extern "C" void art_invoke_super_trampoline_with_access_check(uint32_t, void*);
-  extern "C" void art_invoke_virtual_trampoline_with_access_check(uint32_t, void*);
-  extern "C" void art_lock_object_from_code(void*);
-  extern "C" void art_test_suspend();
-  extern "C" void art_throw_array_bounds_from_code(int32_t index, int32_t limit);
-  extern "C" void art_throw_div_zero_from_code();
-  extern "C" void art_throw_neg_array_size_from_code(int32_t size);
-  extern "C" void art_throw_no_such_method_from_code(int32_t method_idx);
-  extern "C" void art_throw_null_pointer_exception_from_code();
-  extern "C" void art_throw_stack_overflow_from_code(void*);
-  extern "C" void art_throw_verification_error_from_code(int32_t src1, int32_t ref);
-  extern "C" void art_unlock_object_from_code(void*);
-  extern "C" void* art_alloc_array_from_code(uint32_t, void*, int32_t);
-  extern "C" void* art_alloc_array_from_code_with_access_check(uint32_t, void*, int32_t);
-  extern "C" void* art_alloc_object_from_code(uint32_t type_idx, void* method);
-  extern "C" void* art_alloc_object_from_code_with_access_check(uint32_t type_idx, void* method);
-  extern "C" void* art_check_and_alloc_array_from_code(uint32_t, void*, int32_t);
-  extern "C" void* art_check_and_alloc_array_from_code_with_access_check(uint32_t, void*, int32_t);
-  extern "C" void* art_initialize_static_storage_from_code(uint32_t, void*);
-  extern "C" void* art_initialize_type_from_code(uint32_t, void*);
-  extern "C" void* art_initialize_type_and_verify_access_from_code(uint32_t, void*);
-  extern "C" void art_trace_entry_from_code(void*);
-  extern "C" void art_trace_exit_from_code();
-  extern "C" void* art_resolve_string_from_code(void*, uint32_t);
-  extern "C" void art_work_around_app_jni_bugs();
-
-  /* Conversions */
-  extern "C" float __aeabi_i2f(int32_t op1);         // INT_TO_FLOAT
-  extern "C" int32_t __aeabi_f2iz(float op1);        // FLOAT_TO_INT
-  extern "C" float __aeabi_d2f(double op1);          // DOUBLE_TO_FLOAT
-  extern "C" double __aeabi_f2d(float op1);          // FLOAT_TO_DOUBLE
-  extern "C" double __aeabi_i2d(int32_t op1);        // INT_TO_DOUBLE
-  extern "C" int32_t __aeabi_d2iz(double op1);       // DOUBLE_TO_INT
-  extern "C" float __aeabi_l2f(int64_t op1);         // LONG_TO_FLOAT
-  extern "C" double __aeabi_l2d(int64_t op1);        // LONG_TO_DOUBLE
-
-  /* Single-precision FP arithmetics */
-  extern "C" float __aeabi_fadd(float a, float b);   // ADD_FLOAT[_2ADDR]
-  extern "C" float __aeabi_fsub(float a, float b);   // SUB_FLOAT[_2ADDR]
-  extern "C" float __aeabi_fdiv(float a, float b);   // DIV_FLOAT[_2ADDR]
-  extern "C" float __aeabi_fmul(float a, float b);   // MUL_FLOAT[_2ADDR]
-  extern "C" float fmodf(float a, float b);          // REM_FLOAT[_2ADDR]
-
-  /* Double-precision FP arithmetics */
-  extern "C" double __aeabi_dadd(double a, double b); // ADD_DOUBLE[_2ADDR]
-  extern "C" double __aeabi_dsub(double a, double b); // SUB_DOUBLE[_2ADDR]
-  extern "C" double __aeabi_ddiv(double a, double b); // DIV_DOUBLE[_2ADDR]
-  extern "C" double __aeabi_dmul(double a, double b); // MUL_DOUBLE[_2ADDR]
-  extern "C" double fmod(double a, double b);         // REM_DOUBLE[_2ADDR]
-
-  /* Integer arithmetics */
-  extern "C" int __aeabi_idivmod(int32_t op1, int32_t op2);  // REM_INT[_2ADDR|_LIT8|_LIT16]
-  extern "C" int __aeabi_idiv(int32_t op1, int32_t op2);     // DIV_INT[_2ADDR|_LIT8|_LIT16]
-
-  /* Long long arithmetics - REM_LONG[_2ADDR] and DIV_LONG[_2ADDR] */
-  extern "C" long long __aeabi_ldivmod(long long op1, long long op2);
-  extern "C" long long __aeabi_lmul(long long op1, long long op2);
-  extern "C" uint64_t art_shl_long(uint64_t, uint32_t);
-  extern "C" uint64_t art_shr_long(uint64_t, uint32_t);
-  extern "C" uint64_t art_ushr_long(uint64_t, uint32_t);
-
-#endif
-
-#if defined(__mips__)
-  /* Conversions */
-  extern "C" float __floatsisf(int op1);        // INT_TO_FLOAT
-  extern "C" int32_t __fixsfsi(float op1);      // FLOAT_TO_INT
-  extern "C" float __truncdfsf2(double op1);    // DOUBLE_TO_FLOAT
-  extern "C" double __extendsfdf2(float op1);   // FLOAT_TO_DOUBLE
-  extern "C" double __floatsidf(int op1);       // INT_TO_DOUBLE
-  extern "C" int32_t __fixdfsi(double op1);     // DOUBLE_TO_INT
-  extern "C" float __floatdisf(int64_t op1);    // LONG_TO_FLOAT
-  extern "C" double __floatdidf(int64_t op1);   // LONG_TO_DOUBLE
-  extern "C" int64_t __fixsfdi(float op1);      // FLOAT_TO_LONG
-  extern "C" int64_t __fixdfdi(double op1);     // DOUBLE_TO_LONG
-
-  /* Single-precision FP arithmetics */
-  extern "C" float __addsf3(float a, float b);   // ADD_FLOAT[_2ADDR]
-  extern "C" float __subsf3(float a, float b);   // SUB_FLOAT[_2ADDR]
-  extern "C" float __divsf3(float a, float b);   // DIV_FLOAT[_2ADDR]
-  extern "C" float __mulsf3(float a, float b);   // MUL_FLOAT[_2ADDR]
-  extern "C" float fmodf(float a, float b);      // REM_FLOAT[_2ADDR]
-
-  /* Double-precision FP arithmetics */
-  extern "C" double __adddf3(double a, double b); // ADD_DOUBLE[_2ADDR]
-  extern "C" double __subdf3(double a, double b); // SUB_DOUBLE[_2ADDR]
-  extern "C" double __divdf3(double a, double b); // DIV_DOUBLE[_2ADDR]
-  extern "C" double __muldf3(double a, double b); // MUL_DOUBLE[_2ADDR]
-  extern "C" double fmod(double a, double b);     // REM_DOUBLE[_2ADDR]
-
-  /* Long long arithmetics - REM_LONG[_2ADDR] and DIV_LONG[_2ADDR] */
-  extern "C" long long __divdi3(int64_t op1, int64_t op2);
-  extern "C" long long __moddi3(int64_t op1, int64_t op2);
-#endif
-
 #endif  // ART_SRC_RUNTIME_SUPPORT_H_