Merge "Another bug fix for line numbers. Line uses signed in advancing." into dalvik-dev
diff --git a/src/class_linker.cc b/src/class_linker.cc
index 9fd8f0b..53bcf7e 100644
--- a/src/class_linker.cc
+++ b/src/class_linker.cc
@@ -19,6 +19,7 @@
#include "oat_file.h"
#include "object.h"
#include "runtime.h"
+#include "runtime_support.h"
#include "ScopedLocalRef.h"
#include "space.h"
#include "stl_util.h"
@@ -127,6 +128,7 @@
"Ljava/lang/reflect/Constructor;",
"Ljava/lang/reflect/Field;",
"Ljava/lang/reflect/Method;",
+ "Ljava/lang/reflect/Proxy;",
"Ljava/lang/ClassLoader;",
"Ldalvik/system/BaseDexClassLoader;",
"Ldalvik/system/PathClassLoader;",
@@ -420,6 +422,12 @@
Class* Method_class = FindSystemClass("Ljava/lang/reflect/Method;");
CHECK_EQ(java_lang_reflect_Method, Method_class);
+ // End of special init trickery, subsequent classes may be loaded via FindSystemClass
+
+ // Create java.lang.reflect.Proxy root
+ Class* java_lang_reflect_Proxy = FindSystemClass("Ljava/lang/reflect/Proxy;");
+ SetClassRoot(kJavaLangReflectProxy, java_lang_reflect_Proxy);
+
// java.lang.ref classes need to be specially flagged, but otherwise are normal classes
Class* java_lang_ref_Reference = FindSystemClass("Ljava/lang/ref/Reference;");
SetClassRoot(kJavaLangRefReference, java_lang_ref_Reference);
@@ -1291,6 +1299,7 @@
}
const DexFile& ClassLinker::FindDexFile(const DexCache* dex_cache) const {
+ CHECK(dex_cache != NULL);
MutexLock mu(lock_);
for (size_t i = 0; i != dex_caches_.size(); ++i) {
if (dex_caches_[i] == dex_cache) {
@@ -1533,72 +1542,85 @@
}
Class* ClassLinker::CreateProxyClass(String* name, ObjectArray<Class>* interfaces,
- ClassLoader* loader, ObjectArray<Method>* methods, ObjectArray<Object>* throws) {
+ ClassLoader* loader, ObjectArray<Method>* methods, ObjectArray<ObjectArray<Class> >* throws) {
Class* klass = AllocClass(GetClassRoot(kJavaLangClass), sizeof(ProxyClass));
CHECK(klass != NULL);
klass->SetObjectSize(sizeof(Proxy));
- klass->SetDescriptor(intern_table_->InternStrong(name));
+ const char* descriptor = DotToDescriptor(name->ToModifiedUtf8().c_str()).c_str();;
+ klass->SetDescriptor(intern_table_->InternStrong(descriptor));
klass->SetAccessFlags(kAccPublic | kAccFinal);
klass->SetClassLoader(loader);
- klass->SetStatus(Class::kStatusInitialized);
- klass->SetInterfaces(interfaces);
+ klass->SetStatus(Class::kStatusInitialized); // no loading or initializing necessary
+ Class* proxy_class = GetClassRoot(kJavaLangReflectProxy);
+ klass->SetSuperClass(proxy_class); // The super class is java.lang.reflect.Proxy
+ klass->SetInterfaces(interfaces); // The interfaces are the array of interfaces specified
+ // Proxies have 1 direct method, the constructor
klass->SetDirectMethods(AllocObjectArray<Method>(1));
klass->SetDirectMethod(0, CreateProxyConstructor(klass));
+ // Create virtual method using specified prototypes
size_t num_virtual_methods = methods->GetLength();
klass->SetVirtualMethods(AllocObjectArray<Method>(num_virtual_methods));
for (size_t i = 0; i < num_virtual_methods; ++i) {
Method* prototype = methods->Get(i);
klass->SetVirtualMethod(i, CreateProxyMethod(klass, prototype, throws->Get(i)));
}
-
+ // Link the virtual methods, creating vtable and iftables
if (!LinkMethods(klass)) {
DCHECK(Thread::Current()->IsExceptionPending());
return NULL;
}
-
return klass;
}
Method* ClassLinker::CreateProxyConstructor(Class* klass) {
- Method* constructor = AllocMethod();
+ // Create constructor for Proxy that must initialize h
+ Class* proxy_class = GetClassRoot(kJavaLangReflectProxy);
+ ObjectArray<Method>* proxy_direct_methods = proxy_class->GetDirectMethods();
+ CHECK_EQ(proxy_direct_methods->GetLength(), 12);
+ Method* proxy_constructor = proxy_direct_methods->Get(2);
+ // Clone the existing constructor of Proxy (our constructor would just invoke it so steal its
+ // code_ too)
+ Method* constructor = down_cast<Method*>(proxy_constructor->Clone());
+ // Make this constructor public and fix the class to be our Proxy version
+ constructor->SetAccessFlags((constructor->GetAccessFlags() & ~kAccProtected) | kAccPublic);
constructor->SetDeclaringClass(klass);
- constructor->SetName(intern_table_->InternStrong("<init>"));
- constructor->SetSignature(intern_table_->InternStrong("(Ljava/lang/reflect/InvocationHandler;)V"));
- constructor->SetShorty(intern_table_->InternStrong("LV"));
- constructor->SetAccessFlags(kAccPublic | kAccNative);
-
- // TODO: return type
- // TODO: code block
-
+ // Sanity checks
+ CHECK(constructor->IsConstructor());
+ CHECK(constructor->GetName()->Equals("<init>"));
+ CHECK(constructor->GetSignature()->Equals("(Ljava/lang/reflect/InvocationHandler;)V"));
+ DCHECK(constructor->IsPublic());
return constructor;
}
-Method* ClassLinker::CreateProxyMethod(Class* klass, Method* prototype, Object* throws) {
- Method* method = AllocMethod();
+Method* ClassLinker::CreateProxyMethod(Class* klass, Method* prototype,
+ ObjectArray<Class>* throws) {
+ // We steal everything from the prototype (such as DexCache, invoke stub, etc.) then specialise
+ // as necessary
+ Method* method = down_cast<Method*>(prototype->Clone());
+
+ // Set class to be the concrete proxy class and clear the abstract flag, modify exceptions to
+ // the intersection of throw exceptions as defined in Proxy
method->SetDeclaringClass(klass);
- method->SetName(const_cast<String*>(prototype->GetName()));
- method->SetSignature(const_cast<String*>(prototype->GetSignature()));
- method->SetShorty(prototype->GetShorty());
- method->SetAccessFlags(prototype->GetAccessFlags());
+ method->SetAccessFlags((method->GetAccessFlags() & ~kAccAbstract) | kAccFinal);
method->SetExceptionTypes(throws);
- // TODO: return type
- // method->SetReturnTypeIdx(dex_file.GetProtoId(method_id.proto_idx_).return_type_idx_);
+ // At runtime the method looks like a reference and argument saving method, clone the code
+ // related parameters from this method.
+ Method* refs_and_args = Runtime::Current()->GetCalleeSaveMethod(Runtime::kRefsAndArgs);
+ method->SetCoreSpillMask(refs_and_args->GetCoreSpillMask());
+ method->SetFpSpillMask(refs_and_args->GetFpSpillMask());
+ method->SetFrameSizeInBytes(refs_and_args->GetFrameSizeInBytes());
+ method->SetCode(reinterpret_cast<void*>(art_proxy_invoke_handler));
- // TODO: code block
- // method->SetCodeItemOffset(src.code_off_);
- // method->SetDexCacheStrings(klass->GetDexCache()->GetStrings());
- // method->SetDexCacheResolvedTypes(klass->GetDexCache()->GetResolvedTypes());
- // method->SetDexCacheResolvedMethods(klass->GetDexCache()->GetResolvedMethods());
- // method->SetDexCacheResolvedFields(klass->GetDexCache()->GetResolvedFields());
- // method->SetDexCacheCodeAndDirectMethods(klass->GetDexCache()->GetCodeAndDirectMethods());
- // method->SetDexCacheInitializedStaticStorage(klass->GetDexCache()->GetInitializedStaticStorage());
- // method->SetNumRegisters(code_item->registers_size_);
- // method->SetNumIns(code_item->ins_size_);
- // method->SetNumOuts(code_item->outs_size_);
- // LinkCode(method, oat_class.get(), method_index);
+ // Basic sanity
+ DCHECK(method->GetName()->Equals(prototype->GetName()));
+ DCHECK(method->GetSignature()->Equals(prototype->GetSignature()));
+ DCHECK(method->GetShorty()->Equals(prototype->GetShorty()));
+
+ // More complex sanity - via dex cache
+ CHECK_EQ(method->GetReturnType(), prototype->GetReturnType());
return method;
}
@@ -2092,7 +2114,7 @@
size_t j = 0;
for (; j < actual_count; ++j) {
Method* super_method = vtable->Get(j);
- if (local_method->HasSameNameAndDescriptor(super_method)) {
+ if (local_method->HasSameNameAndSignature(super_method)) {
// Verify
if (super_method->IsFinal()) {
ThrowLinkageError("Method %s.%s overrides final method in class %s",
@@ -2212,7 +2234,7 @@
// matter which direction we go. We walk it backward anyway.)
for (k = vtable->GetLength() - 1; k >= 0; --k) {
Method* vtable_method = vtable->Get(k);
- if (interface_method->HasSameNameAndDescriptor(vtable_method)) {
+ if (interface_method->HasSameNameAndSignature(vtable_method)) {
if (!vtable_method->IsPublic()) {
Thread::Current()->ThrowNewExceptionF("Ljava/lang/IllegalAccessError;",
"Implementation not public: %s", PrettyMethod(vtable_method).c_str());
@@ -2225,7 +2247,7 @@
if (k < 0) {
Method* miranda_method = NULL;
for (size_t mir = 0; mir < miranda_list.size(); mir++) {
- if (miranda_list[mir]->HasSameNameAndDescriptor(interface_method)) {
+ if (miranda_list[mir]->HasSameNameAndSignature(interface_method)) {
miranda_method = miranda_list[mir];
break;
}
diff --git a/src/class_linker.h b/src/class_linker.h
index 37802ae..91d6259 100644
--- a/src/class_linker.h
+++ b/src/class_linker.h
@@ -227,7 +227,7 @@
void VerifyClass(Class* klass);
Class* CreateProxyClass(String* name, ObjectArray<Class>* interfaces, ClassLoader* loader,
- ObjectArray<Method>* methods, ObjectArray<Object>* throws);
+ ObjectArray<Method>* methods, ObjectArray<ObjectArray<Class> >* throws);
private:
ClassLinker(InternTable*);
@@ -347,7 +347,7 @@
}
Method* CreateProxyConstructor(Class* klass);
- Method* CreateProxyMethod(Class* klass, Method* prototype, Object* throws);
+ Method* CreateProxyMethod(Class* klass, Method* prototype, ObjectArray<Class>* throws);
// lock to protect ClassLinker state
mutable Mutex lock_;
@@ -377,6 +377,7 @@
kJavaLangReflectConstructor,
kJavaLangReflectField,
kJavaLangReflectMethod,
+ kJavaLangReflectProxy,
kJavaLangClassLoader,
kDalvikSystemBaseDexClassLoader,
kDalvikSystemPathClassLoader,
diff --git a/src/class_linker_test.cc b/src/class_linker_test.cc
index 34e02f0..e604ca0 100644
--- a/src/class_linker_test.cc
+++ b/src/class_linker_test.cc
@@ -864,8 +864,8 @@
Field* s3 = statics->FindStaticField("s3", class_linker_->FindClass("S", class_loader));
EXPECT_TRUE(s3->GetType()->IsPrimitiveShort());
- EXPECT_EQ(65000, s3->GetShort(NULL));
- s3->SetShort(NULL, 65001);
+ EXPECT_EQ(-536, s3->GetShort(NULL));
+ s3->SetShort(NULL, -535);
Field* s4 = statics->FindStaticField("s4", class_linker_->FindClass("I", class_loader));
EXPECT_TRUE(s4->GetType()->IsPrimitiveInt());
@@ -895,7 +895,7 @@
EXPECT_EQ(false, s0->GetBoolean(NULL));
EXPECT_EQ(6, s1->GetByte(NULL));
EXPECT_EQ('b', s2->GetChar(NULL));
- EXPECT_EQ(65001, s3->GetShort(NULL));
+ EXPECT_EQ(-535, s3->GetShort(NULL));
EXPECT_EQ(2000000001, s4->GetInt(NULL));
EXPECT_EQ(0x34567890abcdef12LL, s5->GetLong(NULL));
EXPECT_EQ(0.75, s6->GetFloat(NULL));
diff --git a/src/java_lang_reflect_Proxy.cc b/src/java_lang_reflect_Proxy.cc
index 821bdd8..55ecd08 100644
--- a/src/java_lang_reflect_Proxy.cc
+++ b/src/java_lang_reflect_Proxy.cc
@@ -29,7 +29,7 @@
ObjectArray<Class>* interfaces = Decode<ObjectArray<Class>*>(env, javaInterfaces);
ClassLoader* loader = Decode<ClassLoader*>(env, javaLoader);
ObjectArray<Method>* methods = Decode<ObjectArray<Method>*>(env, javaMethods);
- ObjectArray<Object>* throws = Decode<ObjectArray<Object>*>(env, javaThrows);
+ ObjectArray<ObjectArray<Class> >* throws = Decode<ObjectArray<ObjectArray<Class> >*>(env, javaThrows);
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
Class* result = class_linker->CreateProxyClass(name, interfaces, loader, methods, throws);
return AddLocalReference<jclass>(env, result);
diff --git a/src/jni_internal.cc b/src/jni_internal.cc
index 7e75dff..7ce29d4 100644
--- a/src/jni_internal.cc
+++ b/src/jni_internal.cc
@@ -93,6 +93,7 @@
template ClassLoader* Decode<ClassLoader*>(JNIEnv*, jobject);
template Object* Decode<Object*>(JNIEnv*, jobject);
template ObjectArray<Class>* Decode<ObjectArray<Class>*>(JNIEnv*, jobject);
+template ObjectArray<ObjectArray<Class> >* Decode<ObjectArray<ObjectArray<Class> >*>(JNIEnv*, jobject);
template ObjectArray<Object>* Decode<ObjectArray<Object>*>(JNIEnv*, jobject);
template ObjectArray<StackTraceElement>* Decode<ObjectArray<StackTraceElement>*>(JNIEnv*, jobject);
template ObjectArray<Method>* Decode<ObjectArray<Method>*>(JNIEnv*, jobject);
diff --git a/src/object.cc b/src/object.cc
index aeaa19b..e8aeecd 100644
--- a/src/object.cc
+++ b/src/object.cc
@@ -201,12 +201,12 @@
Set32(object, c);
}
-uint16_t Field::GetShort(const Object* object) const {
+int16_t Field::GetShort(const Object* object) const {
DCHECK(GetType()->IsPrimitiveShort());
return Get32(object);
}
-void Field::SetShort(Object* object, uint16_t s) const {
+void Field::SetShort(Object* object, int16_t s) const {
DCHECK(GetType()->IsPrimitiveShort());
Set32(object, s);
}
@@ -560,9 +560,28 @@
return ShortyCharToSize(GetShorty()->CharAt(0));
}
-bool Method::HasSameNameAndDescriptor(const Method* that) const {
- return (this->GetName()->Equals(that->GetName()) &&
- this->GetSignature()->Equals(that->GetSignature()));
+Method* Method::FindOverriddenMethod() const {
+ if (IsStatic()) {
+ return NULL;
+ }
+ Class* declaring_class = GetDeclaringClass();
+ Class* super_class = declaring_class->GetSuperClass();
+ uint16_t method_index = GetMethodIndex();
+ ObjectArray<Method>* super_class_vtable = super_class->GetVTable();
+ Method* result = NULL;
+ if (super_class_vtable != NULL && method_index < super_class_vtable->GetLength()) {
+ result = super_class_vtable->Get(method_index);
+ } else {
+ ObjectArray<Class>* interfaces = declaring_class->GetInterfaces();
+ String* name = GetName();
+ String* signature = GetSignature();
+ for (int32_t i = 0; i < interfaces->GetLength() && result == NULL; i++) {
+ Class* interface = interfaces->Get(i);
+ result = interface->FindInterfaceMethod(name, signature);
+ }
+ }
+ DCHECK (result == NULL || HasSameNameAndSignature(result));
+ return result;
}
uint32_t Method::ToDexPC(const uintptr_t pc) const {
@@ -990,8 +1009,7 @@
return NULL;
}
-Method* Class::FindInterfaceMethod(const StringPiece& name,
- const StringPiece& signature) {
+Method* Class::FindInterfaceMethod(const StringPiece& name, const StringPiece& signature) const {
// Check the current class before checking the interfaces.
Method* method = FindVirtualMethod(name, signature);
if (method != NULL) {
@@ -1009,6 +1027,24 @@
return NULL;
}
+Method* Class::FindInterfaceMethod(String* name, String* signature) const {
+ // Check the current class before checking the interfaces.
+ Method* method = FindVirtualMethod(name, signature);
+ if (method != NULL) {
+ return method;
+ }
+ int32_t iftable_count = GetIfTableCount();
+ ObjectArray<InterfaceEntry>* iftable = GetIfTable();
+ for (int32_t i = 0; i < iftable_count; i++) {
+ Class* interface = iftable->Get(i)->GetInterface();
+ method = interface->FindVirtualMethod(name, signature);
+ if (method != NULL) {
+ return method;
+ }
+ }
+ return NULL;
+}
+
Method* Class::FindDeclaredDirectMethod(const StringPiece& name,
const StringPiece& signature) {
for (size_t i = 0; i < NumDirectMethods(); ++i) {
@@ -1033,20 +1069,41 @@
}
Method* Class::FindDeclaredVirtualMethod(const StringPiece& name,
- const StringPiece& signature) {
+ const StringPiece& signature) const {
for (size_t i = 0; i < NumVirtualMethods(); ++i) {
Method* method = GetVirtualMethod(i);
- if (method->GetName()->Equals(name) &&
- method->GetSignature()->Equals(signature)) {
+ if (method->GetName()->Equals(name) && method->GetSignature()->Equals(signature)) {
return method;
}
}
return NULL;
}
-Method* Class::FindVirtualMethod(const StringPiece& name,
- const StringPiece& signature) {
- for (Class* klass = this; klass != NULL; klass = klass->GetSuperClass()) {
+Method* Class::FindDeclaredVirtualMethod(String* name, String* signature) const {
+ for (size_t i = 0; i < NumVirtualMethods(); ++i) {
+ Method* method = GetVirtualMethod(i);
+ if (method->GetName() == name && method->GetSignature() == signature) {
+ return method;
+ } else {
+ LOG(INFO) << "Find (" << name->ToModifiedUtf8() << ", " << signature->ToModifiedUtf8()
+ << ") != " << PrettyMethod(method);
+ }
+ }
+ return NULL;
+}
+
+Method* Class::FindVirtualMethod(const StringPiece& name, const StringPiece& signature) const {
+ for (const Class* klass = this; klass != NULL; klass = klass->GetSuperClass()) {
+ Method* method = klass->FindDeclaredVirtualMethod(name, signature);
+ if (method != NULL) {
+ return method;
+ }
+ }
+ return NULL;
+}
+
+Method* Class::FindVirtualMethod(String* name, String* signature) const {
+ for (const Class* klass = this; klass != NULL; klass = klass->GetSuperClass()) {
Method* method = klass->FindDeclaredVirtualMethod(name, signature);
if (method != NULL) {
return method;
@@ -1175,6 +1232,9 @@
template class PrimitiveArray<int64_t>; // LongArray
template class PrimitiveArray<int16_t>; // ShortArray
+// Explicitly instantiate Class[][]
+template class ObjectArray<ObjectArray<Class> >;
+
// TODO: get global references for these
Class* String::java_lang_String_ = NULL;
@@ -1350,6 +1410,15 @@
return result;
}
+bool Throwable::IsCheckedException() const {
+ Class* error = Runtime::Current()->GetClassLinker()->FindSystemClass("Ljava/lang/Error;");
+ if (InstanceOf(error)) {
+ return false;
+ }
+ Class* jlre = Runtime::Current()->GetClassLinker()->FindSystemClass("Ljava/lang/RuntimeException;");
+ return !InstanceOf(jlre);
+}
+
Class* StackTraceElement::java_lang_StackTraceElement_ = NULL;
void StackTraceElement::SetClass(Class* java_lang_StackTraceElement) {
diff --git a/src/object.h b/src/object.h
index a4e9c7a..8f6f75d 100644
--- a/src/object.h
+++ b/src/object.h
@@ -447,8 +447,8 @@
void SetByte(Object* object, int8_t b) const;
uint16_t GetChar(const Object* object) const;
void SetChar(Object* object, uint16_t c) const;
- uint16_t GetShort(const Object* object) const;
- void SetShort(Object* object, uint16_t s) const;
+ int16_t GetShort(const Object* object) const;
+ void SetShort(Object* object, int16_t s) const;
int32_t GetInt(const Object* object) const;
void SetInt(Object* object, int32_t i) const;
int64_t GetLong(const Object* object) const;
@@ -534,7 +534,7 @@
}
// Returns the method name, e.g. "<init>" or "eatLunch"
- const String* GetName() const;
+ String* GetName() const;
void SetName(String* new_name);
@@ -550,11 +550,13 @@
void SetShorty(String* new_shorty);
- const String* GetSignature() const;
+ String* GetSignature() const;
void SetSignature(String* new_signature);
- bool HasSameNameAndDescriptor(const Method* that) const;
+ bool HasSameNameAndSignature(const Method* that) const {
+ return GetName() == that->GetName() && GetSignature() == that->GetSignature();
+ }
uint32_t GetAccessFlags() const;
@@ -704,6 +706,9 @@
ObjectArray<StaticStorageBase>* GetDexCacheInitializedStaticStorage() const;
void SetDexCacheInitializedStaticStorage(ObjectArray<StaticStorageBase>* new_value);
+ // Find the method that this method overrides
+ Method* FindOverriddenMethod() const;
+
void SetReturnTypeIdx(uint32_t new_return_type_idx);
Class* GetReturnType() const;
@@ -949,10 +954,13 @@
SetField32(OFFSET_OF_OBJECT_MEMBER(Method, fp_spill_mask_), fp_spill_mask, false);
}
- void SetExceptionTypes(Object* exception_types) {
- SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Method, java_exception_types_), exception_types, false);
+ ObjectArray<Class>* GetExceptionTypes() const {
+ return GetFieldObject<ObjectArray<Class>*>(
+ OFFSET_OF_OBJECT_MEMBER(Method, java_exception_types_), false);
}
+ void SetExceptionTypes(ObjectArray<Class>* exception_types);
+
ObjectArray<Class>* GetJavaParameterTypes() const {
return GetFieldObject<ObjectArray<Class>*>(
OFFSET_OF_OBJECT_MEMBER(Method, java_parameter_types_), false);
@@ -1083,11 +1091,10 @@
const uint32_t* mapping_table_;
- // For concrete virtual methods, this is the offset of the method
- // in Class::vtable_.
+ // For concrete virtual methods, this is the offset of the method in Class::vtable_.
//
- // For abstract methods in an interface class, this is the offset
- // of the method in "iftable_->Get(n)->GetMethodArray()".
+ // For abstract methods in an interface class, this is the offset of the method in
+ // "iftable_->Get(n)->GetMethodArray()".
uint32_t method_index_;
// The target native method registered with this method
@@ -1722,8 +1729,8 @@
// method for this class.
Method* FindVirtualMethodForInterface(Method* method);
- Method* FindInterfaceMethod(const StringPiece& name,
- const StringPiece& descriptor);
+ Method* FindInterfaceMethod(const StringPiece& name, const StringPiece& descriptor) const;
+ Method* FindInterfaceMethod(String* name, String* descriptor) const;
Method* FindVirtualMethodForVirtualOrInterface(Method* method) {
if (method->IsDirect()) {
@@ -1735,11 +1742,11 @@
return FindVirtualMethodForVirtual(method);
}
- Method* FindDeclaredVirtualMethod(const StringPiece& name,
- const StringPiece& signature);
+ Method* FindDeclaredVirtualMethod(const StringPiece& name, const StringPiece& signature) const;
+ Method* FindDeclaredVirtualMethod(String* name, String* signature) const;
- Method* FindVirtualMethod(const StringPiece& name,
- const StringPiece& descriptor);
+ Method* FindVirtualMethod(const StringPiece& name, const StringPiece& descriptor) const;
+ Method* FindVirtualMethod(String* name, String* descriptor) const;
Method* FindDeclaredDirectMethod(const StringPiece& name,
const StringPiece& signature);
@@ -2529,11 +2536,9 @@
GetField32(OFFSET_OF_OBJECT_MEMBER(Field, offset_), false));
}
-inline const String* Method::GetName() const {
+inline String* Method::GetName() const {
DCHECK(GetDeclaringClass()->IsLoaded() || GetDeclaringClass()->IsErroneous());
- const String* result =
- GetFieldObject<const String*>(
- OFFSET_OF_OBJECT_MEMBER(Method, name_), false);
+ String* result = GetFieldObject<String*>(OFFSET_OF_OBJECT_MEMBER(Method, name_), false);
DCHECK(result != NULL);
return result;
}
@@ -2577,10 +2582,9 @@
SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Method, shorty_), new_shorty, false);
}
-inline const String* Method::GetSignature() const {
+inline String* Method::GetSignature() const {
DCHECK(GetDeclaringClass()->IsLoaded() || GetDeclaringClass()->IsErroneous());
- const String* result =
- GetFieldObject<const String*>(OFFSET_OF_OBJECT_MEMBER(Method, signature_), false);
+ String* result = GetFieldObject<String*>(OFFSET_OF_OBJECT_MEMBER(Method, signature_), false);
DCHECK(result != NULL);
return result;
}
@@ -2590,6 +2594,10 @@
new_signature, false);
}
+inline void Method::SetExceptionTypes(ObjectArray<Class>* exception_types) {
+ SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Method, java_exception_types_), exception_types, false);
+}
+
inline uint32_t Class::GetAccessFlags() const {
// Check class is loaded or this is java.lang.String that has a
// circularity issue during loading the names of its members
@@ -2656,6 +2664,7 @@
new_detail_message, false);
}
+ bool IsCheckedException() const;
private:
// Field order required by test "ValidateFieldOrderOfJavaCppUnionClasses".
Throwable* cause_;
diff --git a/src/object_test.cc b/src/object_test.cc
index a180d5e..e5af663 100644
--- a/src/object_test.cc
+++ b/src/object_test.cc
@@ -278,17 +278,17 @@
Method* m4_2 = klass2->GetVirtualMethod(3);
EXPECT_TRUE(m4_2->GetName()->Equals("m4"));
- EXPECT_TRUE(m1_1->HasSameNameAndDescriptor(m1_2));
- EXPECT_TRUE(m1_2->HasSameNameAndDescriptor(m1_1));
+ EXPECT_TRUE(m1_1->HasSameNameAndSignature(m1_2));
+ EXPECT_TRUE(m1_2->HasSameNameAndSignature(m1_1));
- EXPECT_TRUE(m2_1->HasSameNameAndDescriptor(m2_2));
- EXPECT_TRUE(m2_2->HasSameNameAndDescriptor(m2_1));
+ EXPECT_TRUE(m2_1->HasSameNameAndSignature(m2_2));
+ EXPECT_TRUE(m2_2->HasSameNameAndSignature(m2_1));
- EXPECT_TRUE(m3_1->HasSameNameAndDescriptor(m3_2));
- EXPECT_TRUE(m3_2->HasSameNameAndDescriptor(m3_1));
+ EXPECT_TRUE(m3_1->HasSameNameAndSignature(m3_2));
+ EXPECT_TRUE(m3_2->HasSameNameAndSignature(m3_1));
- EXPECT_TRUE(m4_1->HasSameNameAndDescriptor(m4_2));
- EXPECT_TRUE(m4_2->HasSameNameAndDescriptor(m4_1));
+ EXPECT_TRUE(m4_1->HasSameNameAndSignature(m4_2));
+ EXPECT_TRUE(m4_2->HasSameNameAndSignature(m4_1));
}
diff --git a/src/reflection.cc b/src/reflection.cc
index 1294c08..86b4b09 100644
--- a/src/reflection.cc
+++ b/src/reflection.cc
@@ -70,6 +70,7 @@
// Find the actual implementation of the virtual method.
m = receiver->GetClass()->FindVirtualMethodForVirtualOrInterface(m);
+ mid = reinterpret_cast<jmethodID>(m);
}
// Get our arrays of arguments and their types, and check they're the same size.
@@ -310,13 +311,13 @@
Field* primitive_field = o->GetClass()->GetIFields()->Get(0);
if (src_descriptor->Equals("Ljava/lang/Boolean;")) {
src_class = class_linker->FindPrimitiveClass('Z');
- boxed_value.z = primitive_field->GetBoolean(o);
+ boxed_value.i = primitive_field->GetBoolean(o); // and extend read value to 32bits
} else if (src_descriptor->Equals("Ljava/lang/Byte;")) {
src_class = class_linker->FindPrimitiveClass('B');
- boxed_value.b = primitive_field->GetByte(o);
+ boxed_value.i = primitive_field->GetByte(o); // and extend read value to 32bits
} else if (src_descriptor->Equals("Ljava/lang/Character;")) {
src_class = class_linker->FindPrimitiveClass('C');
- boxed_value.c = primitive_field->GetChar(o);
+ boxed_value.i = primitive_field->GetChar(o); // and extend read value to 32bits
} else if (src_descriptor->Equals("Ljava/lang/Float;")) {
src_class = class_linker->FindPrimitiveClass('F');
boxed_value.f = primitive_field->GetFloat(o);
@@ -331,7 +332,7 @@
boxed_value.j = primitive_field->GetLong(o);
} else if (src_descriptor->Equals("Ljava/lang/Short;")) {
src_class = class_linker->FindPrimitiveClass('S');
- boxed_value.s = primitive_field->GetShort(o);
+ boxed_value.i = primitive_field->GetShort(o); // and extend read value to 32bits
} else {
Thread::Current()->ThrowNewExceptionF("Ljava/lang/IllegalArgumentException;",
"%s is not a boxed primitive type", PrettyDescriptor(src_descriptor).c_str());
diff --git a/src/runtime_support.cc b/src/runtime_support.cc
index ba3e1b4..ccb8dcc 100644
--- a/src/runtime_support.cc
+++ b/src/runtime_support.cc
@@ -901,14 +901,36 @@
return result;
}
+static void ThrowNewUndeclaredThrowableException(Thread* self, JNIEnv* env, Throwable* exception) {
+ ScopedLocalRef<jclass> jlr_UTE_class(env,
+ env->FindClass("java/lang/reflect/UndeclaredThrowableException"));
+ if (jlr_UTE_class.get() == NULL) {
+ LOG(ERROR) << "Couldn't throw new \"java/lang/reflect/UndeclaredThrowableException\"";
+ } else {
+ jmethodID jlre_UTE_constructor = env->GetMethodID(jlr_UTE_class.get(), "<init>",
+ "(Ljava/lang/Throwable;)V");
+ jthrowable jexception = AddLocalReference<jthrowable>(env, exception);
+ ScopedLocalRef<jthrowable> jlr_UTE(env,
+ reinterpret_cast<jthrowable>(env->NewObject(jlr_UTE_class.get(), jlre_UTE_constructor,
+ jexception)));
+ int rc = env->Throw(jlr_UTE.get());
+ if (rc != JNI_OK) {
+ LOG(ERROR) << "Couldn't throw new \"java/lang/reflect/UndeclaredThrowableException\"";
+ }
+ }
+ CHECK(self->IsExceptionPending());
+}
+
// Handler for invocation on proxy methods. On entry a frame will exist for the proxy object method
// which is responsible for recording callee save registers. We explicitly handlerize incoming
// reference arguments (so they survive GC) and create a boxed argument array. Finally we invoke
// the invocation handler which is a field within the proxy object receiver.
extern "C" void artProxyInvokeHandler(Method* proxy_method, Object* receiver,
- byte* stack_args, Thread* self) {
+ Thread* self, byte* stack_args) {
// Register the top of the managed stack
- self->SetTopOfStack(reinterpret_cast<Method**>(stack_args + 8), 0);
+ Method** proxy_sp = reinterpret_cast<Method**>(stack_args - 12);
+ DCHECK_EQ(*proxy_sp, proxy_method);
+ self->SetTopOfStack(proxy_sp, 0);
// TODO: ARM specific
DCHECK_EQ(proxy_method->GetFrameSizeInBytes(), 48u);
// Start new JNI local reference state
@@ -941,7 +963,7 @@
param_index++;
}
// Placing into local references incoming arguments from the caller's stack arguments
- cur_arg += 5; // skip LR, Method* and spills for R1 to R3
+ cur_arg += 11; // skip callee saves, LR, Method* and out arg spills for R1 to R3
while (param_index < num_params) {
if (proxy_method->IsParamAReference(param_index)) {
Object* obj = *reinterpret_cast<Object**>(stack_args + (cur_arg * kPointerSize));
@@ -951,23 +973,31 @@
cur_arg = cur_arg + (proxy_method->IsParamALongOrDouble(param_index) ? 2 : 1);
param_index++;
}
- // Create args array
- ObjectArray<Object>* args =
- Runtime::Current()->GetClassLinker()->AllocObjectArray<Object>(num_params - 1);
- if(args == NULL) {
- CHECK(self->IsExceptionPending());
- return;
- }
// Set up arguments array and place in local IRT during boxing (which may allocate/GC)
jvalue args_jobj[3];
args_jobj[0].l = rcvr_jobj;
args_jobj[1].l = proxy_method_jobj;
- args_jobj[2].l = AddLocalReference<jobjectArray>(env, args);
+ // Args array, if no arguments then NULL (don't include receiver in argument count)
+ args_jobj[2].l = NULL;
+ ObjectArray<Object>* args = NULL;
+ if ((num_params - 1) > 0) {
+ args = Runtime::Current()->GetClassLinker()->AllocObjectArray<Object>(num_params - 1);
+ if(args == NULL) {
+ CHECK(self->IsExceptionPending());
+ return;
+ }
+ args_jobj[2].l = AddLocalReference<jobjectArray>(env, args);
+ }
+ // Convert proxy method into expected interface method
+ Method* interface_method = proxy_method->FindOverriddenMethod();
+ CHECK(interface_method != NULL);
+ args_jobj[1].l = AddLocalReference<jobject>(env, interface_method);
+ LOG(INFO) << "Interface method is " << PrettyMethod(interface_method, true);
// Box arguments
cur_arg = 0; // reset stack location to read to start
// reset index, will index into param type array which doesn't include the receiver
param_index = 0;
- ObjectArray<Class>* param_types = proxy_method->GetJavaParameterTypes();
+ ObjectArray<Class>* param_types = interface_method->GetJavaParameterTypes();
CHECK(param_types != NULL);
// Check number of parameter types agrees with number from the Method - less 1 for the receiver.
CHECK_EQ(static_cast<size_t>(param_types->GetLength()), num_params - 1);
@@ -980,8 +1010,7 @@
JValue val = *reinterpret_cast<JValue*>(stack_args + (cur_arg * kPointerSize));
if (cur_arg == 1 && (param_type->IsPrimitiveLong() || param_type->IsPrimitiveDouble())) {
// 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));
+ uint64_t high_half = *reinterpret_cast<uint32_t*>(stack_args + (13 * kPointerSize));
val.j = (val.j & 0xffffffffULL) | (high_half << 32);
}
BoxPrimitive(env, param_type, val);
@@ -995,8 +1024,8 @@
param_index++;
}
// Placing into local references incoming arguments from the caller's stack arguments
- cur_arg += 5; // skip LR, Method* and spills for R1 to R3
- while (param_index < num_params) {
+ cur_arg += 11; // skip callee saves, LR, Method* and out arg spills for R1 to R3
+ while (param_index < (num_params - 1)) {
Class* param_type = param_types->Get(param_index);
Object* obj;
if (!param_type->IsPrimitive()) {
@@ -1017,13 +1046,13 @@
static jmethodID inv_hand_invoke_mid = NULL;
static jfieldID proxy_inv_hand_fid = NULL;
if (proxy_inv_hand_fid == NULL) {
- ScopedLocalRef<jclass> proxy(env, env->FindClass("java.lang.reflect.Proxy"));
+ ScopedLocalRef<jclass> proxy(env, env->FindClass("java/lang/reflect/Proxy"));
proxy_inv_hand_fid = env->GetFieldID(proxy.get(), "h", "Ljava/lang/reflect/InvocationHandler;");
- ScopedLocalRef<jclass> inv_hand_class(env, env->FindClass("java.lang.reflect.InvocationHandler"));
+ ScopedLocalRef<jclass> inv_hand_class(env, env->FindClass("java/lang/reflect/InvocationHandler"));
inv_hand_invoke_mid = env->GetMethodID(inv_hand_class.get(), "invoke",
"(Ljava/lang/Object;Ljava/lang/reflect/Method;[Ljava/lang/Object;)Ljava/lang/Object;");
}
- DCHECK(env->IsInstanceOf(rcvr_jobj, env->FindClass("java.lang.reflect.Proxy")));
+ DCHECK(env->IsInstanceOf(rcvr_jobj, env->FindClass("java/lang/reflect/Proxy")));
jobject inv_hand = env->GetObjectField(rcvr_jobj, proxy_inv_hand_fid);
// Call InvocationHandler.invoke
jobject result = env->CallObjectMethodA(inv_hand, inv_hand_invoke_mid, args_jobj);
@@ -1032,11 +1061,32 @@
Object* result_ref = self->DecodeJObject(result);
if (result_ref != NULL) {
JValue result_unboxed;
- UnboxPrimitive(env, result_ref, proxy_method->GetReturnType(), result_unboxed);
+ UnboxPrimitive(env, result_ref, interface_method->GetReturnType(), result_unboxed);
*reinterpret_cast<JValue*>(stack_args) = result_unboxed;
} else {
*reinterpret_cast<jobject*>(stack_args) = NULL;
}
+ } else {
+ // In the case of checked exceptions that aren't declared, the exception must be wrapped by
+ // a UndeclaredThrowableException.
+ Throwable* exception = self->GetException();
+ self->ClearException();
+ if (!exception->IsCheckedException()) {
+ self->SetException(exception);
+ } else {
+ ObjectArray<Class>* declared_exceptions = proxy_method->GetExceptionTypes();
+ Class* exception_class = exception->GetClass();
+ bool declares_exception = false;
+ for (int i = 0; i < declared_exceptions->GetLength() && !declares_exception; i++) {
+ Class* declared_exception = declared_exceptions->Get(i);
+ declares_exception = declared_exception->IsAssignableFrom(exception_class);
+ }
+ if (declares_exception) {
+ self->SetException(exception);
+ } else {
+ ThrowNewUndeclaredThrowableException(self, env, exception);
+ }
+ }
}
}
diff --git a/src/runtime_support.h b/src/runtime_support.h
index de41f47..ba0b0f1 100644
--- a/src/runtime_support.h
+++ b/src/runtime_support.h
@@ -32,6 +32,8 @@
/* Helper for both JNI and regular compiled code */
extern "C" void art_deliver_exception_from_code(void*);
+extern "C" void art_proxy_invoke_handler();
+
#if defined(__arm__)
/* Compiler helpers */
extern "C" void* art_alloc_object_from_code(uint32_t type_idx, void* method);
diff --git a/src/runtime_support_asm.S b/src/runtime_support_asm.S
index 2076fad..8ef3da8 100644
--- a/src/runtime_support_asm.S
+++ b/src/runtime_support_asm.S
@@ -485,8 +485,9 @@
add r3, sp, #12 @ pointer to r2/r3/LR/caller's Method**/out-args as second arg
blx artProxyInvokeHandler @ (Method* proxy method, receiver, Thread*, args...)
ldr r12, [r9, #THREAD_EXCEPTION_OFFSET] @ load Thread::Current()->exception_
- ldrd r0, [sp, #12] @ load r0/r1 from r2/r3 that were overwritten with the out args
- RESTORE_REF_AND_ARGS_CALLEE_SAVE_FRAME
+ ldr lr, [sp, #44] @ restore lr
+ ldrd r0, [sp, #12] @ load r0/r1 from r2/r3 that were overwritten with the out args
+ add sp, #48 @ pop frame
cmp r12, #0 @ success if no exception is pending
bxeq lr @ return on success
DELIVER_PENDING_EXCEPTION
@@ -588,4 +589,9 @@
call artDeliverExceptionFromCode // artDeliverExceptionFromCode(Throwable*, Thread*, SP)
int3
+ // TODO
+ .global art_proxy_invoke_handler
+art_proxy_invoke_handler:
+ int3
+
#endif
diff --git a/src/thread.cc b/src/thread.cc
index 62b3290..e143af5 100644
--- a/src/thread.cc
+++ b/src/thread.cc
@@ -1091,15 +1091,17 @@
Method* method = down_cast<Method*>(method_trace->Get(i));
uint32_t native_pc = pc_trace->Get(i);
Class* klass = method->GetDeclaringClass();
- const DexFile& dex_file = class_linker->FindDexFile(klass->GetDexCache());
std::string class_name(PrettyDescriptor(klass->GetDescriptor()));
-
+ int32_t line_number = -1;
+ DexCache* dex_cache = klass->GetDexCache();
+ if (dex_cache != NULL) {
+ const DexFile& dex_file = class_linker->FindDexFile(dex_cache);
+ line_number = dex_file.GetLineNumFromPC(method, method->ToDexPC(native_pc));
+ }
// Allocate element, potentially triggering GC
StackTraceElement* obj =
StackTraceElement::Alloc(String::AllocFromModifiedUtf8(class_name.c_str()),
- method->GetName(),
- klass->GetSourceFile(),
- dex_file.GetLineNumFromPC(method, method->ToDexPC(native_pc)));
+ method->GetName(), klass->GetSourceFile(), line_number);
if (obj == NULL) {
return NULL;
}
diff --git a/test/044-proxy/expected.txt b/test/044-proxy/expected.txt
index 4be26cf..27771ce 100644
--- a/test/044-proxy/expected.txt
+++ b/test/044-proxy/expected.txt
@@ -1,3 +1,7 @@
+ReturnsAndArgPassing.testProxyReturns RUNNING
+ReturnsAndArgPassing.testProxyReturns PASSED
+ReturnsAndArgPassing.testProxyArgPassing RUNNING
+ReturnsAndArgPassing.testProxyArgPassing PASSED
Invoke public abstract void Shapes.circle(int)
0: 3
--- circle 3
@@ -45,10 +49,10 @@
(no args)
Got expected ie
-Proxy methods: [public native boolean $Proxy0.equals(java.lang.Object), public native int $Proxy0.hashCode(), public native java.lang.String $Proxy0.toString(), public native int $Proxy0.rectangle(int,int), public native int $Proxy0.square(int,int), public native int $Proxy0.trapezoid(int,double,int), public native java.lang.String $Proxy0.blob(), public native void $Proxy0.circle(int), public native void $Proxy0.upCheck(), public native void $Proxy0.upChuck(), public native double $Proxy0.blue(int), public native R0aa $Proxy0.checkMe(), public native int $Proxy0.green(double), public native int $Proxy0.mauve(java.lang.String), public native int $Proxy0.red(float)]
+Proxy methods: [public final java.lang.String $Proxy1.blob(), public final double $Proxy1.blue(int), public final R0a $Proxy1.checkMe(), public final R0base $Proxy1.checkMe(), public final R0aa $Proxy1.checkMe(), public final void $Proxy1.circle(int), public final boolean $Proxy1.equals(java.lang.Object), public final int $Proxy1.green(double), public final int $Proxy1.hashCode(), public final int $Proxy1.mauve(java.lang.String), public final int $Proxy1.rectangle(int,int), public final int $Proxy1.red(float), public final int $Proxy1.square(int,int), public final java.lang.String $Proxy1.toString(), public final int $Proxy1.trapezoid(int,double,int), public final void $Proxy1.upCheck() throws java.lang.InterruptedException, public final void $Proxy1.upChuck()]
Decl annos: []
-Param annos (1) : [[]]
-Proxy fields: [private static java.lang.Throwable[][] $Proxy0.throws]
+Param annos (0) : []
+Proxy fields: [private static java.lang.reflect.Method $Proxy1.m0, private static java.lang.reflect.Method $Proxy1.m1, private static java.lang.reflect.Method $Proxy1.m10, private static java.lang.reflect.Method $Proxy1.m11, private static java.lang.reflect.Method $Proxy1.m12, private static java.lang.reflect.Method $Proxy1.m13, private static java.lang.reflect.Method $Proxy1.m14, private static java.lang.reflect.Method $Proxy1.m15, private static java.lang.reflect.Method $Proxy1.m16, private static java.lang.reflect.Method $Proxy1.m2, private static java.lang.reflect.Method $Proxy1.m3, private static java.lang.reflect.Method $Proxy1.m4, private static java.lang.reflect.Method $Proxy1.m5, private static java.lang.reflect.Method $Proxy1.m6, private static java.lang.reflect.Method $Proxy1.m7, private static java.lang.reflect.Method $Proxy1.m8, private static java.lang.reflect.Method $Proxy1.m9]
Dupe threw expected exception
Clash threw expected exception
Clash2 threw expected exception
diff --git a/test/044-proxy/src/BasicTest.java b/test/044-proxy/src/BasicTest.java
index 2a453c4..fa1896f 100644
--- a/test/044-proxy/src/BasicTest.java
+++ b/test/044-proxy/src/BasicTest.java
@@ -22,6 +22,7 @@
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;
+import java.util.Comparator;
/**
* Do some basic tests.
@@ -70,6 +71,11 @@
*/
System.out.println("");
Method[] methods = proxy.getClass().getDeclaredMethods();
+ Arrays.sort(methods, new Comparator<Method>() {
+ public int compare(Method o1, Method o2) {
+ return o1.getName().compareTo(o2.getName());
+ }
+ });
System.out.println("Proxy methods: " + Arrays.deepToString(methods));
Method meth = methods[methods.length -1];
System.out.println("Decl annos: " + Arrays.deepToString(meth.getDeclaredAnnotations()));
@@ -77,6 +83,11 @@
System.out.println("Param annos (" + paramAnnos.length + ") : "
+ Arrays.deepToString(paramAnnos));
Field[] fields = proxy.getClass().getDeclaredFields();
+ Arrays.sort(fields, new Comparator<Field>() {
+ public int compare(Field o1, Field o2) {
+ return o1.getName().compareTo(o2.getName());
+ }
+ });
System.out.println("Proxy fields: " + Arrays.deepToString(fields));
}
diff --git a/test/044-proxy/src/Main.java b/test/044-proxy/src/Main.java
index 01926af..5396ab8 100644
--- a/test/044-proxy/src/Main.java
+++ b/test/044-proxy/src/Main.java
@@ -19,6 +19,7 @@
*/
public class Main {
public static void main(String[] args) {
+ ReturnsAndArgPassing.main(null);
BasicTest.main(null);
Clash.main(null);
Clash2.main(null);
diff --git a/test/044-proxy/src/ReturnsAndArgPassing.java b/test/044-proxy/src/ReturnsAndArgPassing.java
new file mode 100644
index 0000000..6a706cb
--- /dev/null
+++ b/test/044-proxy/src/ReturnsAndArgPassing.java
@@ -0,0 +1,206 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * 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.
+ */
+import java.lang.reflect.*;
+
+/**
+ * @author irogers@google.com (Ian Rogers)
+ */
+public class ReturnsAndArgPassing {
+
+ public static final String testName = "ReturnsAndArgPassing";
+
+ static void check(boolean x) {
+ if (!x) {
+ throw new AssertionError(testName + " Check failed");
+ }
+ }
+
+ interface MyInterface {
+ void voidFoo();
+ void voidBar();
+ boolean booleanFoo();
+ boolean booleanBar();
+ byte byteFoo();
+ byte byteBar();
+ char charFoo();
+ char charBar();
+ short shortFoo();
+ short shortBar();
+ int intFoo();
+ int intBar();
+ long longFoo();
+ long longBar();
+ float floatFoo();
+ float floatBar();
+ double doubleFoo();
+ double doubleBar();
+ Object selectArg(int select, int a, long b, float c, double d, Object x);
+ }
+
+ static int fooInvocations = 0;
+ static int barInvocations = 0;
+
+ static class MyInvocationHandler implements InvocationHandler {
+ public Object invoke(Object proxy, Method method, Object[] args) {
+ check(proxy instanceof Proxy);
+ check(method.getDeclaringClass() == MyInterface.class);
+ String name = method.getName();
+ if (name.endsWith("Foo")) {
+ check(args == null);
+ fooInvocations++;
+ } else if (name.endsWith("Bar")) {
+ check(args == null);
+ barInvocations++;
+ }
+ if (name.equals("voidFoo")) { return null; }
+ else if (name.equals("voidBar")) { return null; }
+ else if (name.equals("booleanFoo")) { return true; }
+ else if (name.equals("booleanBar")) { return false; }
+ else if (name.equals("byteFoo")) { return Byte.MAX_VALUE; }
+ else if (name.equals("byteBar")) { return Byte.MIN_VALUE; }
+ else if (name.equals("charFoo")) { return Character.MAX_VALUE; }
+ else if (name.equals("charBar")) { return Character.MIN_VALUE; }
+ else if (name.equals("shortFoo")) { return Short.MAX_VALUE; }
+ else if (name.equals("shortBar")) { return Short.MIN_VALUE; }
+ else if (name.equals("intFoo")) { return Integer.MAX_VALUE; }
+ else if (name.equals("intBar")) { return Integer.MIN_VALUE; }
+ else if (name.equals("longFoo")) { return Long.MAX_VALUE; }
+ else if (name.equals("longBar")) { return Long.MIN_VALUE; }
+ else if (name.equals("floatFoo")) { return Float.MAX_VALUE; }
+ else if (name.equals("floatBar")) { return Float.MIN_VALUE; }
+ else if (name.equals("doubleFoo")) { return Double.MAX_VALUE; }
+ else if (name.equals("doubleBar")) { return Double.MIN_VALUE; }
+ else if (name.equals("selectArg")) {
+ check(args.length == 6);
+ int select = (Integer)args[0];
+ return args[select];
+ } else {
+ throw new AssertionError("Unexpect method " + method);
+ }
+ }
+ }
+
+ static void testProxyReturns() {
+ System.out.println(testName + ".testProxyReturns RUNNING");
+ MyInvocationHandler myHandler = new MyInvocationHandler();
+ MyInterface proxyMyInterface =
+ (MyInterface)Proxy.newProxyInstance(ReturnsAndArgPassing.class.getClassLoader(),
+ new Class[] { MyInterface.class },
+ myHandler);
+ check(fooInvocations == 0);
+ proxyMyInterface.voidFoo();
+ check(fooInvocations == 1);
+
+ check(barInvocations == 0);
+ proxyMyInterface.voidBar();
+ check(barInvocations == 1);
+
+ check(fooInvocations == 1);
+ check(proxyMyInterface.booleanFoo() == true);
+ check(fooInvocations == 2);
+
+ check(barInvocations == 1);
+ check(proxyMyInterface.booleanBar() == false);
+ check(barInvocations == 2);
+
+ check(fooInvocations == 2);
+ check(proxyMyInterface.byteFoo() == Byte.MAX_VALUE);
+ check(fooInvocations == 3);
+
+ check(barInvocations == 2);
+ check(proxyMyInterface.byteBar() == Byte.MIN_VALUE);
+ check(barInvocations == 3);
+
+ check(fooInvocations == 3);
+ check(proxyMyInterface.charFoo() == Character.MAX_VALUE);
+ check(fooInvocations == 4);
+
+ check(barInvocations == 3);
+ check(proxyMyInterface.charBar() == Character.MIN_VALUE);
+ check(barInvocations == 4);
+
+ check(fooInvocations == 4);
+ check(proxyMyInterface.shortFoo() == Short.MAX_VALUE);
+ check(fooInvocations == 5);
+
+ check(barInvocations == 4);
+ check(proxyMyInterface.shortBar() == Short.MIN_VALUE);
+ check(barInvocations == 5);
+
+ check(fooInvocations == 5);
+ check(proxyMyInterface.intFoo() == Integer.MAX_VALUE);
+ check(fooInvocations == 6);
+
+ check(barInvocations == 5);
+ check(proxyMyInterface.intBar() == Integer.MIN_VALUE);
+ check(barInvocations == 6);
+
+ check(fooInvocations == 6);
+ check(proxyMyInterface.longFoo() == Long.MAX_VALUE);
+ check(fooInvocations == 7);
+
+ check(barInvocations == 6);
+ check(proxyMyInterface.longBar() == Long.MIN_VALUE);
+ check(barInvocations == 7);
+
+ check(fooInvocations == 7);
+ check(proxyMyInterface.floatFoo() == Float.MAX_VALUE);
+ check(fooInvocations == 8);
+
+ check(barInvocations == 7);
+ check(proxyMyInterface.floatBar() == Float.MIN_VALUE);
+ check(barInvocations == 8);
+
+ check(fooInvocations == 8);
+ check(proxyMyInterface.doubleFoo() == Double.MAX_VALUE);
+ check(fooInvocations == 9);
+
+ check(barInvocations == 8);
+ check(proxyMyInterface.doubleBar() == Double.MIN_VALUE);
+ check(barInvocations == 9);
+
+ System.out.println(testName + ".testProxyReturns PASSED");
+ }
+
+ static void testProxyArgPassing() {
+ System.out.println(testName + ".testProxyArgPassing RUNNING");
+ MyInvocationHandler myHandler = new MyInvocationHandler();
+ MyInterface proxyMyInterface =
+ (MyInterface)Proxy.newProxyInstance(ReturnsAndArgPassing.class.getClassLoader(),
+ new Class[] { MyInterface.class },
+ myHandler);
+
+ check((Integer)proxyMyInterface.selectArg(0, Integer.MAX_VALUE, Long.MAX_VALUE,
+ Float.MAX_VALUE, Double.MAX_VALUE, Object.class) == 0);
+ check((Integer)proxyMyInterface.selectArg(1, Integer.MAX_VALUE, Long.MAX_VALUE,
+ Float.MAX_VALUE, Double.MAX_VALUE, Object.class) == Integer.MAX_VALUE);
+ check((Long)proxyMyInterface.selectArg(2, Integer.MAX_VALUE, Long.MAX_VALUE,
+ Float.MAX_VALUE, Double.MAX_VALUE, Object.class) == Long.MAX_VALUE);
+ check((Float)proxyMyInterface.selectArg(3, Integer.MAX_VALUE, Long.MAX_VALUE,
+ Float.MAX_VALUE, Double.MAX_VALUE, Object.class) == Float.MAX_VALUE);
+ check((Double)proxyMyInterface.selectArg(4, Integer.MAX_VALUE, Long.MAX_VALUE,
+ Float.MAX_VALUE, Double.MAX_VALUE, Object.class) == Double.MAX_VALUE);
+ check(proxyMyInterface.selectArg(5, Integer.MAX_VALUE, Long.MAX_VALUE,
+ Float.MAX_VALUE, Double.MAX_VALUE, Object.class) == Object.class);
+
+ System.out.println(testName + ".testProxyArgPassing PASSED");
+ }
+
+ public static void main(String args[]) {
+ testProxyReturns();
+ testProxyArgPassing();
+ }
+}