Various tidy ups, add LIKELY/UNLIKELY macros.
Make more aggressive use of the dex cache when we have it.
Change-Id: I125a7bac031f7f0cec68194b5380bdfd83c92833
diff --git a/src/class_linker.h b/src/class_linker.h
index a3157cc..7c5acaa 100644
--- a/src/class_linker.h
+++ b/src/class_linker.h
@@ -21,6 +21,7 @@
#include <utility>
#include <vector>
+#include "dex_cache.h"
#include "dex_file.h"
#include "heap.h"
#include "macros.h"
@@ -74,11 +75,14 @@
// result in the DexCache. The referrer is used to identify the
// target DexCache and ClassLoader to use for resolution.
String* ResolveString(uint32_t string_idx, const Method* referrer) {
- Class* declaring_class = referrer->GetDeclaringClass();
- DexCache* dex_cache = declaring_class->GetDexCache();
- // TODO: we could check for a dex cache hit here
- const DexFile& dex_file = FindDexFile(dex_cache);
- return ResolveString(dex_file, string_idx, dex_cache);
+ String* resolved_string = referrer->GetDexCacheStrings()->Get(string_idx);
+ if (UNLIKELY(resolved_string == NULL)) {
+ Class* declaring_class = referrer->GetDeclaringClass();
+ DexCache* dex_cache = declaring_class->GetDexCache();
+ const DexFile& dex_file = FindDexFile(dex_cache);
+ resolved_string = ResolveString(dex_file, string_idx, dex_cache);
+ }
+ return resolved_string;
}
// Resolve a String with the given index from the DexFile, storing the
@@ -101,21 +105,27 @@
// result in the DexCache. The referrer is used to identify the
// target DexCache and ClassLoader to use for resolution.
Class* ResolveType(uint32_t type_idx, const Method* referrer) {
- Class* declaring_class = referrer->GetDeclaringClass();
- DexCache* dex_cache = declaring_class->GetDexCache();
- // TODO: we could check for a dex cache hit here
- const ClassLoader* class_loader = declaring_class->GetClassLoader();
- const DexFile& dex_file = FindDexFile(dex_cache);
- return ResolveType(dex_file, type_idx, dex_cache, class_loader);
+ Class* resolved_type = referrer->GetDexCacheResolvedTypes()->Get(type_idx);
+ if (UNLIKELY(resolved_type == NULL)) {
+ Class* declaring_class = referrer->GetDeclaringClass();
+ DexCache* dex_cache = declaring_class->GetDexCache();
+ const ClassLoader* class_loader = declaring_class->GetClassLoader();
+ const DexFile& dex_file = FindDexFile(dex_cache);
+ resolved_type = ResolveType(dex_file, type_idx, dex_cache, class_loader);
+ }
+ return resolved_type;
}
Class* ResolveType(uint32_t type_idx, const Field* referrer) {
Class* declaring_class = referrer->GetDeclaringClass();
DexCache* dex_cache = declaring_class->GetDexCache();
- // TODO: we could check for a dex cache hit here
- const ClassLoader* class_loader = declaring_class->GetClassLoader();
- const DexFile& dex_file = FindDexFile(dex_cache);
- return ResolveType(dex_file, type_idx, dex_cache, class_loader);
+ Class* resolved_type = dex_cache->GetResolvedType(type_idx);
+ if (UNLIKELY(resolved_type == NULL)) {
+ const ClassLoader* class_loader = declaring_class->GetClassLoader();
+ const DexFile& dex_file = FindDexFile(dex_cache);
+ resolved_type = ResolveType(dex_file, type_idx, dex_cache, class_loader);
+ }
+ return resolved_type;
}
// Resolve a type with the given ID from the DexFile, storing the
@@ -139,21 +149,27 @@
bool is_direct);
Method* ResolveMethod(uint32_t method_idx, const Method* referrer, bool is_direct) {
- Class* declaring_class = referrer->GetDeclaringClass();
- DexCache* dex_cache = declaring_class->GetDexCache();
- // TODO: we could check for a dex cache hit here
- const ClassLoader* class_loader = declaring_class->GetClassLoader();
- const DexFile& dex_file = FindDexFile(dex_cache);
- return ResolveMethod(dex_file, method_idx, dex_cache, class_loader, is_direct);
+ Method* resolved_method = referrer->GetDexCacheResolvedMethods()->Get(method_idx);
+ if (UNLIKELY(resolved_method == NULL)) {
+ Class* declaring_class = referrer->GetDeclaringClass();
+ DexCache* dex_cache = declaring_class->GetDexCache();
+ const ClassLoader* class_loader = declaring_class->GetClassLoader();
+ const DexFile& dex_file = FindDexFile(dex_cache);
+ resolved_method = ResolveMethod(dex_file, method_idx, dex_cache, class_loader, is_direct);
+ }
+ return resolved_method;
}
Field* ResolveField(uint32_t field_idx, const Method* referrer, bool is_static) {
- Class* declaring_class = referrer->GetDeclaringClass();
- DexCache* dex_cache = declaring_class->GetDexCache();
- // TODO: we could check for a dex cache hit here
- const ClassLoader* class_loader = declaring_class->GetClassLoader();
- const DexFile& dex_file = FindDexFile(dex_cache);
- return ResolveField(dex_file, field_idx, dex_cache, class_loader, is_static);
+ Field* resolved_field = referrer->GetDexCacheResolvedFields()->Get(field_idx);
+ if (UNLIKELY(resolved_field == NULL)) {
+ Class* declaring_class = referrer->GetDeclaringClass();
+ DexCache* dex_cache = declaring_class->GetDexCache();
+ const ClassLoader* class_loader = declaring_class->GetClassLoader();
+ const DexFile& dex_file = FindDexFile(dex_cache);
+ resolved_field = ResolveField(dex_file, field_idx, dex_cache, class_loader, is_static);
+ }
+ return resolved_field;
}
// Resolve a field with a given ID from the DexFile, storing the
diff --git a/src/logging.h b/src/logging.h
index b6306b2..a0b290d 100644
--- a/src/logging.h
+++ b/src/logging.h
@@ -25,12 +25,13 @@
#include "macros.h"
#define CHECK(x) \
- if (!(x)) \
+ if (UNLIKELY(!(x))) \
::art::LogMessage(__FILE__, __LINE__, FATAL, -1).stream() \
<< "Check failed: " #x << " "
#define CHECK_OP(LHS, RHS, OP) \
- for (::art::EagerEvaluator<typeof(LHS), typeof(RHS)> _values(LHS, RHS); !(_values.lhs OP _values.rhs); ) \
+ for (::art::EagerEvaluator<typeof(LHS), typeof(RHS)> _values(LHS, RHS); \
+ UNLIKELY(!(_values.lhs OP _values.rhs)); ) \
::art::LogMessage(__FILE__, __LINE__, FATAL, -1).stream() \
<< "Check failed: " << #LHS << " " << #OP << " " << #RHS \
<< " (" #LHS "=" << _values.lhs << ", " #RHS "=" << _values.rhs << ") "
@@ -43,7 +44,7 @@
#define CHECK_GT(x, y) CHECK_OP(x, y, >)
#define CHECK_STROP(s1, s2, sense) \
- if ((strcmp(s1, s2) == 0) != sense) \
+ if (UNLIKELY((strcmp(s1, s2) == 0) != sense)) \
LOG(FATAL) << "Check failed: " \
<< "\"" << s1 << "\"" \
<< (sense ? " == " : " != ") \
diff --git a/src/macros.h b/src/macros.h
index 9c5124b..f016f9e 100644
--- a/src/macros.h
+++ b/src/macros.h
@@ -125,4 +125,7 @@
#define PACKED __attribute__ ((__packed__))
+#define LIKELY(x) __builtin_expect((x),true)
+#define UNLIKELY(x) __builtin_expect((x),false)
+
#endif // ART_SRC_MACROS_H_
diff --git a/src/object.h b/src/object.h
index c8f4375..35e355d 100644
--- a/src/object.h
+++ b/src/object.h
@@ -294,7 +294,7 @@
Heap::VerifyObject(this);
const byte* raw_addr = reinterpret_cast<const byte*>(this) + field_offset.Int32Value();
const int32_t* word_addr = reinterpret_cast<const int32_t*>(raw_addr);
- if (is_volatile) {
+ if (UNLIKELY(is_volatile)) {
return android_atomic_acquire_load(word_addr);
} else {
return *word_addr;
@@ -307,7 +307,7 @@
}
byte* raw_addr = reinterpret_cast<byte*>(this) + field_offset.Int32Value();
uint32_t* word_addr = reinterpret_cast<uint32_t*>(raw_addr);
- if (is_volatile) {
+ if (UNLIKELY(is_volatile)) {
/*
* TODO: add an android_atomic_synchronization_store() function and
* use it in the 32-bit volatile set handlers. On some platforms we
@@ -325,7 +325,7 @@
Heap::VerifyObject(this);
const byte* raw_addr = reinterpret_cast<const byte*>(this) + field_offset.Int32Value();
const int64_t* addr = reinterpret_cast<const int64_t*>(raw_addr);
- if (is_volatile) {
+ if (UNLIKELY(is_volatile)) {
uint64_t result = QuasiAtomicRead64(addr);
ANDROID_MEMBAR_FULL();
return result;
@@ -338,7 +338,7 @@
Heap::VerifyObject(this);
byte* raw_addr = reinterpret_cast<byte*>(this) + field_offset.Int32Value();
int64_t* addr = reinterpret_cast<int64_t*>(raw_addr);
- if (is_volatile) {
+ if (UNLIKELY(is_volatile)) {
ANDROID_MEMBAR_STORE();
QuasiAtomicSwap64(new_value, addr);
// Post-store barrier not required due to use of atomic op or mutex.
@@ -1148,7 +1148,7 @@
protected:
bool IsValidIndex(int32_t index) const {
- if (index < 0 || index >= length_) {
+ if (UNLIKELY(index < 0 || index >= length_)) {
return ThrowArrayIndexOutOfBoundsException(index);
}
return true;
@@ -1565,14 +1565,6 @@
}
}
- // Assignable test for code, won't throw. Null and equality tests already performed
- static uint32_t IsAssignableFromCode(const Class* klass, const Class* ref_class)
- {
- DCHECK(klass != NULL);
- DCHECK(ref_class != NULL);
- return klass->IsAssignableFrom(ref_class) ? 1 : 0;
- }
-
Class* GetSuperClass() const {
// Can only get super class for loaded classes (hack for when runtime is
// initializing)
diff --git a/src/object_test.cc b/src/object_test.cc
index 1c317e6..a180d5e 100644
--- a/src/object_test.cc
+++ b/src/object_test.cc
@@ -310,10 +310,10 @@
ASSERT_TRUE(x != NULL);
ASSERT_TRUE(y != NULL);
- EXPECT_EQ(1U, Class::IsAssignableFromCode(X, x->GetClass()));
- EXPECT_EQ(0U, Class::IsAssignableFromCode(Y, x->GetClass()));
- EXPECT_EQ(1U, Class::IsAssignableFromCode(X, y->GetClass()));
- EXPECT_EQ(1U, Class::IsAssignableFromCode(Y, y->GetClass()));
+ EXPECT_EQ(1U, IsAssignableFromCode(X, x->GetClass()));
+ EXPECT_EQ(0U, IsAssignableFromCode(Y, x->GetClass()));
+ EXPECT_EQ(1U, IsAssignableFromCode(X, y->GetClass()));
+ EXPECT_EQ(1U, IsAssignableFromCode(Y, y->GetClass()));
EXPECT_TRUE(x->InstanceOf(X));
EXPECT_FALSE(x->InstanceOf(Y));
diff --git a/src/runtime_support.cc b/src/runtime_support.cc
index 964c646..8608eff 100644
--- a/src/runtime_support.cc
+++ b/src/runtime_support.cc
@@ -16,7 +16,9 @@
#include "runtime_support.h"
+#include "dex_cache.h"
#include "dex_verifier.h"
+#include "macros.h"
#include "reflection.h"
#include "ScopedLocalRef.h"
@@ -38,6 +40,18 @@
LOG(INFO) << "Info: " << info;
}
+void ObjectInitFromCode(Object* o) {
+ Class* c = o->GetClass();
+ if (UNLIKELY(c->IsFinalizable())) {
+ Heap::AddFinalizerReference(o);
+ }
+ /*
+ * NOTE: once debugger/profiler support is added, we'll need to check
+ * here and branch to actual compiled object.<init> to handle any
+ * breakpoint/logging activites if either is active.
+ */
+}
+
// Return value helper for jobject return types
extern Object* DecodeJObjectInThread(Thread* thread, jobject obj) {
if (thread->IsExceptionPending()) {
@@ -347,7 +361,7 @@
} else {
is_static = type == Runtime::kStaticMethod;
}
- // Placing into local references incoming arguments from the caller's register arguments
+ // Place into local references incoming arguments from the caller's register arguments
size_t cur_arg = 1; // skip method_idx in R0, first arg is in R1
if (!is_static) {
Object* obj = reinterpret_cast<Object*>(regs[cur_arg]);
@@ -370,7 +384,7 @@
}
cur_arg = cur_arg + (c == 'J' || c == 'D' ? 2 : 1);
}
- // Placing into local references incoming arguments from the caller's stack arguments
+ // Place into local references incoming arguments from the caller's stack arguments
cur_arg += 5; // skip LR, Method* and spills for R1 to R3
while (shorty_index < shorty_len) {
char c = shorty[shorty_index];
@@ -383,12 +397,12 @@
}
// Resolve method filling in dex cache
Method* called = linker->ResolveMethod(method_idx, *caller_sp, true);
- if (!thread->IsExceptionPending()) {
+ if (LIKELY(!thread->IsExceptionPending())) {
// We got this far, ensure that the declaring class is initialized
linker->EnsureInitialized(called->GetDeclaringClass(), true);
}
void* code;
- if (thread->IsExceptionPending()) {
+ if (UNLIKELY(thread->IsExceptionPending())) {
// Something went wrong, go into deliver exception with the pending exception in r0
code = reinterpret_cast<void*>(art_deliver_exception_from_code);
regs[0] = reinterpret_cast<uintptr_t>(thread->GetException());
@@ -427,15 +441,33 @@
*/
}
+// Fast path field resolution that can't throw exceptions
+static Field* FindFieldFast(uint32_t field_idx, const Method* referrer) {
+ Field* resolved_field = referrer->GetDexCacheResolvedFields()->Get(field_idx);
+ if (UNLIKELY(resolved_field == NULL)) {
+ return NULL;
+ }
+ Class* fields_class = resolved_field->GetDeclaringClass();
+ // Check class is initilaized or initializing
+ if (UNLIKELY(!fields_class->IsInitializing())) {
+ return NULL;
+ }
+ return resolved_field;
+}
+
+// Slow path field resolution and declaring class initialization
Field* FindFieldFromCode(uint32_t field_idx, const Method* referrer, bool is_static) {
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
- Field* f = class_linker->ResolveField(field_idx, referrer, is_static);
- if (f != NULL) {
- Class* c = f->GetDeclaringClass();
+ Field* resolved_field = class_linker->ResolveField(field_idx, referrer, is_static);
+ if (LIKELY(resolved_field != NULL)) {
+ Class* fields_class = resolved_field->GetDeclaringClass();
// If the class is already initializing, we must be inside <clinit>, or
// we'd still be waiting for the lock.
- if (c->GetStatus() == Class::kStatusInitializing || class_linker->EnsureInitialized(c, true)) {
- return f;
+ if (fields_class->IsInitializing()) {
+ return resolved_field;
+ }
+ if(Runtime::Current()->GetClassLinker()->EnsureInitialized(fields_class, true)) {
+ return resolved_field;
}
}
DCHECK(Thread::Current()->IsExceptionPending()); // Throw exception and unwind
@@ -444,17 +476,28 @@
extern "C" Field* artFindInstanceFieldFromCode(uint32_t field_idx, const Method* referrer,
Thread* self, Method** sp) {
- FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
- return FindFieldFromCode(field_idx, referrer, false);
+ Field* resolved_field = FindFieldFast(field_idx, referrer);
+ if (UNLIKELY(resolved_field == NULL)) {
+ FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
+ resolved_field = FindFieldFromCode(field_idx, referrer, false);
+ }
+ return resolved_field;
}
extern "C" uint32_t artGet32StaticFromCode(uint32_t field_idx, const Method* referrer,
Thread* self, Method** sp) {
+ Field* field = FindFieldFast(field_idx, referrer);
+ if (LIKELY(field != NULL)) {
+ Class* type = field->GetType();
+ if (LIKELY(type->IsPrimitive() && type->PrimitiveSize() == sizeof(int32_t))) {
+ return field->Get32(NULL);
+ }
+ }
FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
- Field* field = FindFieldFromCode(field_idx, referrer, true);
+ field = FindFieldFromCode(field_idx, referrer, true);
if (field != NULL) {
Class* type = field->GetType();
- if (!type->IsPrimitive() || type->PrimitiveSize() != sizeof(int64_t)) {
+ if (!type->IsPrimitive() || type->PrimitiveSize() != sizeof(int32_t)) {
self->ThrowNewExceptionF("Ljava/lang/NoSuchFieldError;",
"Attempted read of 32-bit primitive on field '%s'",
PrettyField(field, true).c_str());
@@ -467,8 +510,15 @@
extern "C" uint64_t artGet64StaticFromCode(uint32_t field_idx, const Method* referrer,
Thread* self, Method** sp) {
+ Field* field = FindFieldFast(field_idx, referrer);
+ if (LIKELY(field != NULL)) {
+ Class* type = field->GetType();
+ if (LIKELY(type->IsPrimitive() && type->PrimitiveSize() == sizeof(int64_t))) {
+ return field->Get64(NULL);
+ }
+ }
FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
- Field* field = FindFieldFromCode(field_idx, referrer, true);
+ field = FindFieldFromCode(field_idx, referrer, true);
if (field != NULL) {
Class* type = field->GetType();
if (!type->IsPrimitive() || type->PrimitiveSize() != sizeof(int64_t)) {
@@ -484,8 +534,15 @@
extern "C" Object* artGetObjStaticFromCode(uint32_t field_idx, const Method* referrer,
Thread* self, Method** sp) {
+ Field* field = FindFieldFast(field_idx, referrer);
+ if (LIKELY(field != NULL)) {
+ Class* type = field->GetType();
+ if (LIKELY(!type->IsPrimitive())) {
+ return field->GetObj(NULL);
+ }
+ }
FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
- Field* field = FindFieldFromCode(field_idx, referrer, true);
+ field = FindFieldFromCode(field_idx, referrer, true);
if (field != NULL) {
Class* type = field->GetType();
if (type->IsPrimitive()) {
@@ -501,8 +558,16 @@
extern "C" int artSet32StaticFromCode(uint32_t field_idx, const Method* referrer,
uint32_t new_value, Thread* self, Method** sp) {
+ Field* field = FindFieldFast(field_idx, referrer);
+ if (LIKELY(field != NULL)) {
+ Class* type = field->GetType();
+ if (LIKELY(type->IsPrimitive() && type->PrimitiveSize() == sizeof(int32_t))) {
+ field->Set32(NULL, new_value);
+ return 0; // success
+ }
+ }
FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
- Field* field = FindFieldFromCode(field_idx, referrer, true);
+ field = FindFieldFromCode(field_idx, referrer, true);
if (field != NULL) {
Class* type = field->GetType();
if (!type->IsPrimitive() || type->PrimitiveSize() != sizeof(int32_t)) {
@@ -519,11 +584,19 @@
extern "C" int artSet64StaticFromCode(uint32_t field_idx, const Method* referrer,
uint64_t new_value, Thread* self, Method** sp) {
- FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
- Field* field = FindFieldFromCode(field_idx, referrer, true);
- if (field != NULL) {
+ Field* field = FindFieldFast(field_idx, referrer);
+ if (LIKELY(field != NULL)) {
Class* type = field->GetType();
- if (!type->IsPrimitive() || type->PrimitiveSize() != sizeof(int64_t)) {
+ if (LIKELY(type->IsPrimitive() && type->PrimitiveSize() == sizeof(int64_t))) {
+ field->Set64(NULL, new_value);
+ return 0; // success
+ }
+ }
+ FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
+ field = FindFieldFromCode(field_idx, referrer, true);
+ if (LIKELY(field != NULL)) {
+ Class* type = field->GetType();
+ if (UNLIKELY(!type->IsPrimitive() || type->PrimitiveSize() != sizeof(int64_t))) {
self->ThrowNewExceptionF("Ljava/lang/NoSuchFieldError;",
"Attempted write of 64-bit primitive to field '%s'",
PrettyField(field, true).c_str());
@@ -537,8 +610,16 @@
extern "C" int artSetObjStaticFromCode(uint32_t field_idx, const Method* referrer,
Object* new_value, Thread* self, Method** sp) {
+ Field* field = FindFieldFast(field_idx, referrer);
+ if (LIKELY(field != NULL)) {
+ Class* type = field->GetType();
+ if (LIKELY(!type->IsPrimitive())) {
+ field->SetObj(NULL, new_value);
+ return 0; // success
+ }
+ }
FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
- Field* field = FindFieldFromCode(field_idx, referrer, true);
+ field = FindFieldFromCode(field_idx, referrer, true);
if (field != NULL) {
Class* type = field->GetType();
if (type->IsPrimitive()) {
@@ -555,11 +636,12 @@
// 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.
-extern "C" Object* artAllocObjectFromCode(uint32_t type_idx, Method* method, Thread* self, Method** sp) {
+extern "C" Object* artAllocObjectFromCode(uint32_t type_idx, Method* method,
+ Thread* self, Method** sp) {
FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
Class* klass = method->GetDexCacheResolvedTypes()->Get(type_idx);
Runtime* runtime = Runtime::Current();
- if (klass == NULL) {
+ if (UNLIKELY(klass == NULL)) {
klass = runtime->GetClassLinker()->ResolveType(type_idx, method);
if (klass == NULL) {
DCHECK(self->IsExceptionPending());
@@ -575,19 +657,19 @@
Array* CheckAndAllocArrayFromCode(uint32_t type_idx, Method* method, int32_t component_count,
Thread* self) {
- if (component_count < 0) {
+ if (UNLIKELY(component_count < 0)) {
self->ThrowNewExceptionF("Ljava/lang/NegativeArraySizeException;", "%d", component_count);
return NULL; // Failure
}
Class* klass = method->GetDexCacheResolvedTypes()->Get(type_idx);
- if (klass == NULL) { // Not in dex cache so try to resolve
+ 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
}
}
- if (klass->IsPrimitive() && !klass->IsPrimitiveInt()) {
+ if (UNLIKELY(klass->IsPrimitive() && !klass->IsPrimitiveInt())) {
if (klass->IsPrimitiveLong() || klass->IsPrimitiveDouble()) {
Thread::Current()->ThrowNewExceptionF("Ljava/lang/RuntimeException;",
"Bad filled array request for type %s",
@@ -599,7 +681,7 @@
}
return NULL; // Failure
} else {
- CHECK(klass->IsArrayClass()) << PrettyClass(klass);
+ DCHECK(klass->IsArrayClass()) << PrettyClass(klass);
return Array::Alloc(klass, component_count);
}
}
@@ -616,13 +698,13 @@
extern "C" Array* artAllocArrayFromCode(uint32_t type_idx, Method* method, int32_t component_count,
Thread* self, Method** sp) {
FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
- if (component_count < 0) {
+ 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 (klass == NULL) { // Not in dex cache so try to resolve
+ 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());
@@ -633,14 +715,21 @@
return Array::Alloc(klass, component_count);
}
+// Assignable test for code, won't throw. Null and equality tests already performed
+uint32_t IsAssignableFromCode(const Class* klass, const Class* ref_class) {
+ DCHECK(klass != NULL);
+ DCHECK(ref_class != NULL);
+ return klass->IsAssignableFrom(ref_class) ? 1 : 0;
+}
+
// Check whether it is safe to cast one class to the other, throw exception and return -1 on failure
extern "C" int artCheckCastFromCode(const Class* a, const Class* b, Thread* self, Method** sp) {
- FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
DCHECK(a->IsClass()) << PrettyClass(a);
DCHECK(b->IsClass()) << PrettyClass(b);
- if (b->IsAssignableFrom(a)) {
+ if (LIKELY(b->IsAssignableFrom(a))) {
return 0; // Success
} else {
+ FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
Thread::Current()->ThrowNewExceptionF("Ljava/lang/ClassCastException;",
"%s cannot be cast to %s",
PrettyDescriptor(a->GetDescriptor()).c_str(),
@@ -653,14 +742,14 @@
// Returns 0 on success and -1 if an exception is pending.
extern "C" int artCanPutArrayElementFromCode(const Object* element, const Class* array_class,
Thread* self, Method** sp) {
- FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
DCHECK(array_class != NULL);
// element can't be NULL as we catch this is screened in runtime_support
Class* element_class = element->GetClass();
Class* component_type = array_class->GetComponentType();
- if (component_type->IsAssignableFrom(element_class)) {
+ if (LIKELY(component_type->IsAssignableFrom(element_class))) {
return 0; // Success
} else {
+ FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
Thread::Current()->ThrowNewExceptionF("Ljava/lang/ArrayStoreException;",
"Cannot store an object of type %s in to an array of type %s",
PrettyDescriptor(element_class->GetDescriptor()).c_str(),
@@ -672,7 +761,7 @@
Class* InitializeStaticStorage(uint32_t type_idx, const Method* referrer, Thread* self) {
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
Class* klass = class_linker->ResolveType(type_idx, referrer);
- if (klass == NULL) {
+ if (UNLIKELY(klass == NULL)) {
CHECK(self->IsExceptionPending());
return NULL; // Failure - Indicate to caller to deliver exception
}
@@ -754,14 +843,14 @@
Thread* self, Method** sp) {
FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
DCHECK_EQ(table[0], 0x0300);
- if (array == NULL) {
+ if (UNLIKELY(array == NULL)) {
Thread::Current()->ThrowNewExceptionF("Ljava/lang/NullPointerException;",
"null array in fill array");
return -1; // Error
}
DCHECK(array->IsArrayInstance() && !array->IsObjectArray());
uint32_t size = (uint32_t)table[2] | (((uint32_t)table[3]) << 16);
- if (static_cast<int32_t>(size) > array->GetLength()) {
+ if (UNLIKELY(static_cast<int32_t>(size) > array->GetLength())) {
Thread::Current()->ThrowNewExceptionF("Ljava/lang/ArrayIndexOutOfBoundsException;",
"failed array fill. length=%d; index=%d", array->GetLength(), size);
return -1; // Error
@@ -774,32 +863,39 @@
// See comments in runtime_support_asm.S
extern "C" uint64_t artFindInterfaceMethodInCacheFromCode(uint32_t method_idx,
- Object* this_object ,
+ Object* this_object,
+ Method* caller_method,
Thread* thread, Method** sp) {
- FinishCalleeSaveFrameSetup(thread, sp, Runtime::kRefsAndArgs);
- if (this_object == NULL) {
- thread->ThrowNewExceptionF("Ljava/lang/NullPointerException;",
- "null receiver during interface dispatch");
- return 0;
+ Method* interface_method = caller_method->GetDexCacheResolvedMethods()->Get(method_idx);
+ Method* found_method = NULL; // The found method
+ if (LIKELY(interface_method != NULL && this_object != NULL)) {
+ found_method = this_object->GetClass()->FindVirtualMethodForInterface(interface_method);
}
- ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
- Frame frame = thread->GetTopOfStack(); // Compute calling method
- frame.Next();
- Method* caller_method = frame.GetMethod();
- Method* interface_method = class_linker->ResolveMethod(method_idx, caller_method, false);
- if (interface_method == NULL) {
- // Could not resolve interface method. Throw error and unwind
- CHECK(thread->IsExceptionPending());
- return 0;
+ if (UNLIKELY(found_method == NULL)) {
+ FinishCalleeSaveFrameSetup(thread, sp, Runtime::kRefsAndArgs);
+ if (this_object == NULL) {
+ thread->ThrowNewExceptionF("Ljava/lang/NullPointerException;",
+ "null receiver during interface dispatch");
+ return 0;
+ }
+ if (interface_method == NULL) {
+ ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+ interface_method = class_linker->ResolveMethod(method_idx, caller_method, false);
+ if (interface_method == NULL) {
+ // Could not resolve interface method. Throw error and unwind
+ CHECK(thread->IsExceptionPending());
+ return 0;
+ }
+ }
+ found_method = this_object->GetClass()->FindVirtualMethodForInterface(interface_method);
+ if (found_method == NULL) {
+ CHECK(thread->IsExceptionPending());
+ return 0;
+ }
}
- Method* method = this_object->GetClass()->FindVirtualMethodForInterface(interface_method);
- if (method == NULL) {
- CHECK(thread->IsExceptionPending());
- return 0;
- }
- const void* code = method->GetCode();
+ const void* code = found_method->GetCode();
- uint32_t method_uint = reinterpret_cast<uint32_t>(method);
+ uint32_t method_uint = reinterpret_cast<uint32_t>(found_method);
uint64_t code_uint = reinterpret_cast<uint32_t>(code);
uint64_t result = ((code_uint << 32) | method_uint);
return result;
@@ -886,7 +982,7 @@
// long/double split over regs and stack, mask in high half from stack arguments
// (7 = 2 reg args + LR + Method* + 3 arg reg spill slots)
uint64_t high_half = *reinterpret_cast<uint32_t*>(stack_args + (7 * kPointerSize));
- val.j = (val.j & 0xFFFFFFFFull) | (high_half << 32);
+ val.j = (val.j & 0xffffffffULL) | (high_half << 32);
}
BoxPrimitive(env, param_type, val);
if (self->IsExceptionPending()) {
diff --git a/src/runtime_support.h b/src/runtime_support.h
index c1e0b27..de41f47 100644
--- a/src/runtime_support.h
+++ b/src/runtime_support.h
@@ -21,6 +21,8 @@
void* UnresolvedDirectMethodTrampolineFromCode(int32_t, void*, Thread*, Runtime::TrampolineType);
extern Class* InitializeStaticStorage(uint32_t type_idx, const Method* referrer, Thread* self);
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 ResolveMethodFromCode(Method* method, uint32_t method_idx);
extern void LockObjectFromCode(Thread* thread, Object* obj);
extern int64_t D2L(double d);
diff --git a/src/runtime_support_asm.S b/src/runtime_support_asm.S
index cc854e9..2076fad 100644
--- a/src/runtime_support_asm.S
+++ b/src/runtime_support_asm.S
@@ -176,9 +176,10 @@
*/
art_invoke_interface_trampoline:
SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME @ save callee saves in case allocation triggers GC
- mov r2, r9 @ pass Thread::Current
- mov r3, sp @ pass SP
- bl artFindInterfaceMethodInCacheFromCode @ (method_idx, this, Thread*, SP)
+ ldr r2, [sp, #48] @ pass caller Method*
+ mov r3, r9 @ pass Thread::Current
+ str sp, [sp, #0] @ pass SP
+ bl artFindInterfaceMethodInCacheFromCode @ (method_idx, this, caller, Thread*, SP)
mov r12, r1 @ save r0->code_
RESTORE_REF_AND_ARGS_CALLEE_SAVE_FRAME
cmp r0, #0 @ did we find the target?
@@ -392,19 +393,20 @@
.global art_resolve_string_from_code
.extern artResolveStringFromCode
/*
- * Entry from managed code to resolve a string, this stub will
- * allocate a String and deliver an exception on error. On
- * success the String is returned.
+ * Entry from managed code to resolve a string, this stub will allocate a String and deliver an
+ * exception on error. On success the String is returned. R0 holds the referring method,
+ * R1 holds the string index. The fast path check for hit in strings cache has already been
+ * performed.
*/
art_resolve_string_from_code:
- SETUP_REF_ONLY_CALLEE_SAVE_FRAME @ save callee saves in case of GC
- mov r2, r9 @ pass Thread::Current
- mov r3, sp @ pass SP
- @ artResolveStringFromCode(Method* referrer, uint32_t type_idx, Thread*, SP)
+ SETUP_REF_ONLY_CALLEE_SAVE_FRAME @ save callee saves in case of GC
+ mov r2, r9 @ pass Thread::Current
+ mov r3, sp @ pass SP
+ @ artResolveStringFromCode(Method* referrer, uint32_t string_idx, Thread*, SP)
bl artResolveStringFromCode
RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
- cmp r0, #0 @ success if result is non-null
- bxne lr @ return on success
+ cmp r0, #0 @ success if result is non-null
+ bxne lr @ return on success
DELIVER_PENDING_EXCEPTION
.global art_alloc_object_from_code
diff --git a/src/thread.cc b/src/thread.cc
index 6473df0..3c19fe4 100644
--- a/src/thread.cc
+++ b/src/thread.cc
@@ -62,19 +62,6 @@
static Method* gThreadGroup_removeThread = NULL;
static Method* gUncaughtExceptionHandler_uncaughtException = NULL;
-// TODO: move to appropriate location
-static void ObjectInitFromCode(Object* o) {
- Class* c = o->GetClass();
- if (c->IsFinalizable()) {
- Heap::AddFinalizerReference(o);
- }
- /*
- * NOTE: once debugger/profiler support is added, we'll need to check
- * here and branch to actual compiled object.<init> to handle any
- * breakpoint/logging activites if either is active.
- */
-}
-
void Thread::InitFunctionPointers() {
#if defined(__arm__)
pShlLong = art_shl_long;
@@ -137,7 +124,7 @@
pDeliverException = art_deliver_exception_from_code;
pFindNativeMethod = FindNativeMethod;
pInitializeTypeFromCode = InitializeTypeFromCode;
- pInstanceofNonTrivialFromCode = Class::IsAssignableFromCode;
+ pInstanceofNonTrivialFromCode = IsAssignableFromCode;
pObjectInit = ObjectInitFromCode;
pResolveMethodFromCode = ResolveMethodFromCode;
pThrowAbstractMethodErrorFromCode = ThrowAbstractMethodErrorFromCode;