summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRicardo Cerqueira <cyanogenmod@cerqueira.org>2014-06-03 01:23:27 +0100
committerRicardo Cerqueira <cyanogenmod@cerqueira.org>2014-06-03 01:23:27 +0100
commit6ae6d126ba3b50d16b6ba61f39c3982a34a49eec (patch)
treef588c43e574217cd38777f8282314d250d9dbc6a
parent1ca6a11a61b57edea370adf4454876ccf869d92e (diff)
parentd5e4ac0abdeeb4dc13bd05a40bf496299a787536 (diff)
downloadandroid_art-6ae6d126ba3b50d16b6ba61f39c3982a34a49eec.tar.gz
android_art-6ae6d126ba3b50d16b6ba61f39c3982a34a49eec.tar.bz2
android_art-6ae6d126ba3b50d16b6ba61f39c3982a34a49eec.zip
Android 4.4.3 release 1
-rw-r--r--compiler/dex/quick/arm/utility_arm.cc3
-rw-r--r--compiler/dex/quick/gen_common.cc34
-rw-r--r--compiler/dex/quick/gen_invoke.cc9
-rw-r--r--compiler/dex/quick/mips/mips_lir.h2
-rw-r--r--compiler/dex/quick/mir_to_lir.h2
-rw-r--r--compiler/dex/quick/x86/assemble_x86.cc11
-rw-r--r--compiler/dex/quick/x86/call_x86.cc6
-rw-r--r--compiler/dex/quick/x86/utility_x86.cc1
-rw-r--r--compiler/dex/quick/x86/x86_lir.h1
-rw-r--r--runtime/jni_internal.cc4
-rw-r--r--runtime/mirror/class-inl.h2
-rw-r--r--runtime/oat.cc2
-rw-r--r--runtime/thread.cc52
-rw-r--r--test/018-stack-overflow/expected.txt3
-rw-r--r--test/018-stack-overflow/src/Main.java37
-rw-r--r--test/040-miranda/expected.txt2
-rw-r--r--test/040-miranda/src/Main.java13
-rw-r--r--test/044-proxy/expected.txt5
-rw-r--r--test/044-proxy/src/BasicTest.java22
-rw-r--r--test/JniTest/JniTest.java34
-rw-r--r--test/JniTest/jni_test.cc44
21 files changed, 239 insertions, 50 deletions
diff --git a/compiler/dex/quick/arm/utility_arm.cc b/compiler/dex/quick/arm/utility_arm.cc
index c63de69284..f29e04b0fa 100644
--- a/compiler/dex/quick/arm/utility_arm.cc
+++ b/compiler/dex/quick/arm/utility_arm.cc
@@ -223,6 +223,9 @@ LIR* ArmMir2Lir::OpReg(OpKind op, int r_dest_src) {
case kOpBlx:
opcode = kThumbBlxR;
break;
+ case kOpBx:
+ opcode = kThumbBx;
+ break;
default:
LOG(FATAL) << "Bad opcode " << op;
}
diff --git a/compiler/dex/quick/gen_common.cc b/compiler/dex/quick/gen_common.cc
index f018c61819..8e31a25d92 100644
--- a/compiler/dex/quick/gen_common.cc
+++ b/compiler/dex/quick/gen_common.cc
@@ -16,6 +16,7 @@
#include "dex/compiler_ir.h"
#include "dex/compiler_internals.h"
+#include "dex/quick/arm/arm_lir.h"
#include "dex/quick/mir_to_lir-inl.h"
#include "entrypoints/quick/quick_entrypoints.h"
#include "mirror/array.h"
@@ -544,7 +545,9 @@ void Mir2Lir::HandleThrowLaunchPads() {
ThreadOffset func_offset(-1);
int v1 = lab->operands[2];
int v2 = lab->operands[3];
- bool target_x86 = (cu_->instruction_set == kX86);
+ const bool target_x86 = cu_->instruction_set == kX86;
+ const bool target_arm = cu_->instruction_set == kArm || cu_->instruction_set == kThumb2;
+ const bool target_mips = cu_->instruction_set == kMips;
switch (lab->operands[0]) {
case kThrowNullPointer:
func_offset = QUICK_ENTRYPOINT_OFFSET(pThrowNullPointer);
@@ -602,21 +605,40 @@ void Mir2Lir::HandleThrowLaunchPads() {
func_offset =
QUICK_ENTRYPOINT_OFFSET(pThrowNoSuchMethod);
break;
- case kThrowStackOverflow:
+ case kThrowStackOverflow: {
func_offset = QUICK_ENTRYPOINT_OFFSET(pThrowStackOverflow);
// Restore stack alignment
+ int r_tgt = 0;
+ const int spill_size = (num_core_spills_ + num_fp_spills_) * 4;
if (target_x86) {
- OpRegImm(kOpAdd, TargetReg(kSp), frame_size_);
+ // - 4 to leave link register on stack.
+ OpRegImm(kOpAdd, TargetReg(kSp), frame_size_ - 4);
+ ClobberCalleeSave();
+ } else if (target_arm) {
+ r_tgt = r12;
+ LoadWordDisp(TargetReg(kSp), spill_size - 4, TargetReg(kLr));
+ OpRegImm(kOpAdd, TargetReg(kSp), spill_size);
+ ClobberCalleeSave();
+ LoadWordDisp(rARM_SELF, func_offset.Int32Value(), r_tgt);
} else {
- OpRegImm(kOpAdd, TargetReg(kSp), (num_core_spills_ + num_fp_spills_) * 4);
+ DCHECK(target_mips);
+ DCHECK_EQ(num_fp_spills_, 0); // FP spills currently don't happen on mips.
+ // LR is offset 0 since we push in reverse order.
+ LoadWordDisp(TargetReg(kSp), 0, TargetReg(kLr));
+ OpRegImm(kOpAdd, TargetReg(kSp), spill_size);
+ ClobberCalleeSave();
+ r_tgt = CallHelperSetup(func_offset); // Doesn't clobber LR.
+ DCHECK_NE(r_tgt, TargetReg(kLr));
}
- break;
+ CallHelper(r_tgt, func_offset, false /* MarkSafepointPC */, false /* UseLink */);
+ continue;
+ }
default:
LOG(FATAL) << "Unexpected throw kind: " << lab->operands[0];
}
ClobberCalleeSave();
int r_tgt = CallHelperSetup(func_offset);
- CallHelper(r_tgt, func_offset, true /* MarkSafepointPC */);
+ CallHelper(r_tgt, func_offset, true /* MarkSafepointPC */, true /* UseLink */);
}
}
diff --git a/compiler/dex/quick/gen_invoke.cc b/compiler/dex/quick/gen_invoke.cc
index 2a0a23c7cd..3a39669103 100644
--- a/compiler/dex/quick/gen_invoke.cc
+++ b/compiler/dex/quick/gen_invoke.cc
@@ -33,7 +33,7 @@ namespace art {
/*
* To save scheduling time, helper calls are broken into two parts: generation of
- * the helper target address, and the actuall call to the helper. Because x86
+ * the helper target address, and the actual call to the helper. Because x86
* has a memory call operation, part 1 is a NOP for x86. For other targets,
* load arguments between the two parts.
*/
@@ -42,12 +42,13 @@ int Mir2Lir::CallHelperSetup(ThreadOffset helper_offset) {
}
/* NOTE: if r_tgt is a temp, it will be freed following use */
-LIR* Mir2Lir::CallHelper(int r_tgt, ThreadOffset helper_offset, bool safepoint_pc) {
+LIR* Mir2Lir::CallHelper(int r_tgt, ThreadOffset helper_offset, bool safepoint_pc, bool use_link) {
LIR* call_inst;
+ OpKind op = use_link ? kOpBlx : kOpBx;
if (cu_->instruction_set == kX86) {
- call_inst = OpThreadMem(kOpBlx, helper_offset);
+ call_inst = OpThreadMem(op, helper_offset);
} else {
- call_inst = OpReg(kOpBlx, r_tgt);
+ call_inst = OpReg(op, r_tgt);
FreeTemp(r_tgt);
}
if (safepoint_pc) {
diff --git a/compiler/dex/quick/mips/mips_lir.h b/compiler/dex/quick/mips/mips_lir.h
index 278fcefcbf..dfa837cfbb 100644
--- a/compiler/dex/quick/mips/mips_lir.h
+++ b/compiler/dex/quick/mips/mips_lir.h
@@ -138,7 +138,6 @@ namespace art {
#define r_FRESULT1 r_F1
// Regs not used for Mips.
-#define rMIPS_LR INVALID_REG
#define rMIPS_PC INVALID_REG
// RegisterLocation templates return values (r_V0, or r_V0/r_V1).
@@ -278,6 +277,7 @@ enum MipsNativeRegisterPool {
#define rMIPS_RET1 r_RESULT1
#define rMIPS_INVOKE_TGT r_T9
#define rMIPS_COUNT INVALID_REG
+#define rMIPS_LR r_RA
enum MipsShiftEncodings {
kMipsLsl = 0x0,
diff --git a/compiler/dex/quick/mir_to_lir.h b/compiler/dex/quick/mir_to_lir.h
index a37ebd173f..d41204fc46 100644
--- a/compiler/dex/quick/mir_to_lir.h
+++ b/compiler/dex/quick/mir_to_lir.h
@@ -432,7 +432,7 @@ class Mir2Lir : public Backend {
// Shared by all targets - implemented in gen_invoke.cc.
int CallHelperSetup(ThreadOffset helper_offset);
- LIR* CallHelper(int r_tgt, ThreadOffset helper_offset, bool safepoint_pc);
+ LIR* CallHelper(int r_tgt, ThreadOffset helper_offset, bool safepoint_pc, bool use_link = true);
void CallRuntimeHelperImm(ThreadOffset helper_offset, int arg0, bool safepoint_pc);
void CallRuntimeHelperReg(ThreadOffset helper_offset, int arg0, bool safepoint_pc);
void CallRuntimeHelperRegLocation(ThreadOffset helper_offset, RegLocation arg0,
diff --git a/compiler/dex/quick/x86/assemble_x86.cc b/compiler/dex/quick/x86/assemble_x86.cc
index e8834320a9..93612dcf50 100644
--- a/compiler/dex/quick/x86/assemble_x86.cc
+++ b/compiler/dex/quick/x86/assemble_x86.cc
@@ -319,6 +319,7 @@ ENCODING_MAP(Cmp, IS_LOAD, 0, 0,
{ kX86Jmp8, kJmp, IS_UNARY_OP | IS_BRANCH | NEEDS_FIXUP, { 0, 0, 0xEB, 0, 0, 0, 0, 0 }, "Jmp8", "!0t" },
{ kX86Jmp32, kJmp, IS_UNARY_OP | IS_BRANCH | NEEDS_FIXUP, { 0, 0, 0xE9, 0, 0, 0, 0, 0 }, "Jmp32", "!0t" },
{ kX86JmpR, kJmp, IS_UNARY_OP | IS_BRANCH | REG_USE0, { 0, 0, 0xFF, 0, 0, 4, 0, 0 }, "JmpR", "!0r" },
+ { kX86JmpT, kJmp, IS_UNARY_OP | IS_BRANCH | IS_LOAD, { THREAD_PREFIX, 0, 0xFF, 0, 0, 4, 0, 0 }, "JmpT", "fs:[!0d]" },
{ kX86CallR, kCall, IS_UNARY_OP | IS_BRANCH | REG_USE0, { 0, 0, 0xE8, 0, 0, 0, 0, 0 }, "CallR", "!0r" },
{ kX86CallM, kCall, IS_BINARY_OP | IS_BRANCH | IS_LOAD | REG_USE0, { 0, 0, 0xFF, 0, 0, 2, 0, 0 }, "CallM", "[!0r+!1d]" },
{ kX86CallA, kCall, IS_QUAD_OP | IS_BRANCH | IS_LOAD | REG_USE01, { 0, 0, 0xFF, 0, 0, 2, 0, 0 }, "CallA", "[!0r+!1r<<!2d+!3d]" },
@@ -451,6 +452,8 @@ int X86Mir2Lir::GetInsnSize(LIR* lir) {
return 2; // opcode + rel8
} else if (lir->opcode == kX86Jmp32) {
return 5; // opcode + rel32
+ } else if (lir->opcode == kX86JmpT) {
+ return ComputeSize(entry, 0, 0x12345678, false); // displacement size is always 32bit
} else {
DCHECK(lir->opcode == kX86JmpR);
return 2; // opcode + modrm
@@ -1349,7 +1352,13 @@ AssemblerStatus X86Mir2Lir::AssembleInstructions(uintptr_t start_addr) {
EmitRegCond(entry, lir->operands[0], lir->operands[1]);
break;
case kJmp: // lir operands - 0: rel
- EmitJmp(entry, lir->operands[0]);
+ if (entry->opcode == kX86JmpT) {
+ // This works since the instruction format for jmp and call is basically the same and
+ // EmitCallThread loads opcode info.
+ EmitCallThread(entry, lir->operands[0]);
+ } else {
+ EmitJmp(entry, lir->operands[0]);
+ }
break;
case kJcc: // lir operands - 0: rel, 1: CC, target assigned
EmitJcc(entry, lir->operands[0], lir->operands[1]);
diff --git a/compiler/dex/quick/x86/call_x86.cc b/compiler/dex/quick/x86/call_x86.cc
index 2be2aa9a0e..67388666b4 100644
--- a/compiler/dex/quick/x86/call_x86.cc
+++ b/compiler/dex/quick/x86/call_x86.cc
@@ -224,15 +224,15 @@ void X86Mir2Lir::GenEntrySequence(RegLocation* ArgLocs, RegLocation rl_method) {
LockTemp(rX86_ARG2);
/* Build frame, return address already on stack */
+ // TODO: 64 bit.
OpRegImm(kOpSub, rX86_SP, frame_size_ - 4);
/*
* We can safely skip the stack overflow check if we're
* a leaf *and* our frame size < fudge factor.
*/
- bool skip_overflow_check = (mir_graph_->MethodIsLeaf() &&
- (static_cast<size_t>(frame_size_) <
- Thread::kStackOverflowReservedBytes));
+ const bool skip_overflow_check = (mir_graph_->MethodIsLeaf() &&
+ (static_cast<size_t>(frame_size_) < Thread::kStackOverflowReservedBytes));
NewLIR0(kPseudoMethodEntry);
/* Spill core callee saves */
SpillCoreRegs();
diff --git a/compiler/dex/quick/x86/utility_x86.cc b/compiler/dex/quick/x86/utility_x86.cc
index c519bfec44..d03d4f8577 100644
--- a/compiler/dex/quick/x86/utility_x86.cc
+++ b/compiler/dex/quick/x86/utility_x86.cc
@@ -296,6 +296,7 @@ LIR* X86Mir2Lir::OpThreadMem(OpKind op, ThreadOffset thread_offset) {
X86OpCode opcode = kX86Bkpt;
switch (op) {
case kOpBlx: opcode = kX86CallT; break;
+ case kOpBx: opcode = kX86JmpT; break;
default:
LOG(FATAL) << "Bad opcode: " << op;
break;
diff --git a/compiler/dex/quick/x86/x86_lir.h b/compiler/dex/quick/x86/x86_lir.h
index 643a3d5b8f..8a813e88ea 100644
--- a/compiler/dex/quick/x86/x86_lir.h
+++ b/compiler/dex/quick/x86/x86_lir.h
@@ -362,6 +362,7 @@ enum X86OpCode {
kX86Jcc8, kX86Jcc32, // jCC rel8/32; lir operands - 0: rel, 1: CC, target assigned
kX86Jmp8, kX86Jmp32, // jmp rel8/32; lir operands - 0: rel, target assigned
kX86JmpR, // jmp reg; lir operands - 0: reg
+ kX86JmpT, // jmp fs:[disp]; fs: is equal to Thread::Current(); lir operands - 0: disp
kX86CallR, // call reg; lir operands - 0: reg
kX86CallM, // call [base + disp]; lir operands - 0: base, 1: disp
kX86CallA, // call [base + index * scale + disp]
diff --git a/runtime/jni_internal.cc b/runtime/jni_internal.cc
index 412f96e4af..df863f07b7 100644
--- a/runtime/jni_internal.cc
+++ b/runtime/jni_internal.cc
@@ -291,8 +291,8 @@ static jfieldID FindFieldID(const ScopedObjectAccess& soa, jclass jni_class, con
Class* field_type;
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
if (sig[1] != '\0') {
- ClassLoader* cl = GetClassLoader(soa);
- field_type = class_linker->FindClass(sig, cl);
+ SirtRef<mirror::ClassLoader> class_loader(soa.Self(), c->GetClassLoader());
+ field_type = class_linker->FindClass(sig, class_loader.get());
} else {
field_type = class_linker->FindPrimitiveClass(*sig);
}
diff --git a/runtime/mirror/class-inl.h b/runtime/mirror/class-inl.h
index 1e1138745d..998ebe1a8f 100644
--- a/runtime/mirror/class-inl.h
+++ b/runtime/mirror/class-inl.h
@@ -241,7 +241,7 @@ inline ArtMethod* Class::FindVirtualMethodForVirtualOrInterface(ArtMethod* metho
if (method->IsDirect()) {
return method;
}
- if (method->GetDeclaringClass()->IsInterface()) {
+ if (method->GetDeclaringClass()->IsInterface() && !method->IsMiranda()) {
return FindVirtualMethodForInterface(method);
}
return FindVirtualMethodForVirtual(method);
diff --git a/runtime/oat.cc b/runtime/oat.cc
index c01f77c364..6fe5d1097b 100644
--- a/runtime/oat.cc
+++ b/runtime/oat.cc
@@ -22,7 +22,7 @@
namespace art {
const uint8_t OatHeader::kOatMagic[] = { 'o', 'a', 't', '\n' };
-const uint8_t OatHeader::kOatVersion[] = { '0', '0', '7', '\0' };
+const uint8_t OatHeader::kOatVersion[] = { '0', '0', '8', '\0' };
OatHeader::OatHeader() {
memset(this, 0, sizeof(*this));
diff --git a/runtime/thread.cc b/runtime/thread.cc
index 60a3bf8196..25418a9758 100644
--- a/runtime/thread.cc
+++ b/runtime/thread.cc
@@ -1332,7 +1332,7 @@ class BuildInternalStackTraceVisitor : public StackVisitor {
return true; // Ignore runtime frames (in particular callee save).
}
method_trace_->Set(count_, m);
- dex_pc_trace_->Set(count_, GetDexPc());
+ dex_pc_trace_->Set(count_, m->IsProxyMethod() ? DexFile::kDexNoIndex : GetDexPc());
++count_;
return true;
}
@@ -1384,7 +1384,6 @@ jobjectArray Thread::InternalStackTraceToStackTraceElementArray(JNIEnv* env, job
mirror::ObjectArray<mirror::Object>* method_trace =
soa.Decode<mirror::ObjectArray<mirror::Object>*>(internal);
int32_t depth = method_trace->GetLength() - 1;
- mirror::IntArray* pc_trace = down_cast<mirror::IntArray*>(method_trace->Get(depth));
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
@@ -1413,19 +1412,34 @@ jobjectArray Thread::InternalStackTraceToStackTraceElementArray(JNIEnv* env, job
for (int32_t i = 0; i < depth; ++i) {
// Prepare parameters for StackTraceElement(String cls, String method, String file, int line)
mirror::ArtMethod* method = down_cast<mirror::ArtMethod*>(method_trace->Get(i));
- mh.ChangeMethod(method);
- uint32_t dex_pc = pc_trace->Get(i);
- int32_t line_number = mh.GetLineNumFromDexPC(dex_pc);
- // Allocate element, potentially triggering GC
- // TODO: reuse class_name_object via Class::name_?
- const char* descriptor = mh.GetDeclaringClassDescriptor();
- CHECK(descriptor != NULL);
- std::string class_name(PrettyDescriptor(descriptor));
- SirtRef<mirror::String> class_name_object(soa.Self(),
- mirror::String::AllocFromModifiedUtf8(soa.Self(),
- class_name.c_str()));
- if (class_name_object.get() == NULL) {
- return NULL;
+ MethodHelper mh(method);
+ int32_t line_number;
+ SirtRef<mirror::String> class_name_object(soa.Self(), nullptr);
+ SirtRef<mirror::String> source_name_object(soa.Self(), nullptr);
+ if (method->IsProxyMethod()) {
+ line_number = -1;
+ class_name_object.reset(method->GetDeclaringClass()->GetName());
+ // source_name_object intentionally left null for proxy methods
+ } else {
+ mirror::IntArray* pc_trace = down_cast<mirror::IntArray*>(method_trace->Get(depth));
+ uint32_t dex_pc = pc_trace->Get(i);
+ line_number = mh.GetLineNumFromDexPC(dex_pc);
+ // Allocate element, potentially triggering GC
+ // TODO: reuse class_name_object via Class::name_?
+ const char* descriptor = mh.GetDeclaringClassDescriptor();
+ CHECK(descriptor != nullptr);
+ std::string class_name(PrettyDescriptor(descriptor));
+ class_name_object.reset(mirror::String::AllocFromModifiedUtf8(soa.Self(), class_name.c_str()));
+ if (class_name_object.get() == nullptr) {
+ return nullptr;
+ }
+ const char* source_file = mh.GetDeclaringClassSourceFile();
+ if (source_file != nullptr) {
+ source_name_object.reset(mirror::String::AllocFromModifiedUtf8(soa.Self(), source_file));
+ if (source_name_object.get() == nullptr) {
+ return nullptr;
+ }
+ }
}
const char* method_name = mh.GetName();
CHECK(method_name != NULL);
@@ -1435,14 +1449,8 @@ jobjectArray Thread::InternalStackTraceToStackTraceElementArray(JNIEnv* env, job
if (method_name_object.get() == NULL) {
return NULL;
}
- const char* source_file = mh.GetDeclaringClassSourceFile();
- SirtRef<mirror::String> source_name_object(soa.Self(), mirror::String::AllocFromModifiedUtf8(soa.Self(),
- source_file));
mirror::StackTraceElement* obj = mirror::StackTraceElement::Alloc(soa.Self(),
- class_name_object.get(),
- method_name_object.get(),
- source_name_object.get(),
- line_number);
+ class_name_object.get(), method_name_object.get(), source_name_object.get(), line_number);
if (obj == NULL) {
return NULL;
}
diff --git a/test/018-stack-overflow/expected.txt b/test/018-stack-overflow/expected.txt
index 7797816785..98b45b7b21 100644
--- a/test/018-stack-overflow/expected.txt
+++ b/test/018-stack-overflow/expected.txt
@@ -1,2 +1,3 @@
-caught SOE
+caught SOE in testSelfRecursion
+caught SOE in testMutualRecursion
SOE test done
diff --git a/test/018-stack-overflow/src/Main.java b/test/018-stack-overflow/src/Main.java
index f79c269c85..41adabc9ff 100644
--- a/test/018-stack-overflow/src/Main.java
+++ b/test/018-stack-overflow/src/Main.java
@@ -19,17 +19,46 @@
*/
public class Main {
public static void main(String args[]) {
+ testSelfRecursion();
+ testMutualRecursion();
+ System.out.println("SOE test done");
+ }
+
+ private static void testSelfRecursion() {
try {
stackOverflowTestSub(0.0, 0.0, 0.0);
}
catch (StackOverflowError soe) {
- System.out.println("caught SOE");
+ System.out.println("caught SOE in testSelfRecursion");
}
- System.out.println("SOE test done");
}
- private static void stackOverflowTestSub(double pad1, double pad2,
- double pad3) {
+ private static void stackOverflowTestSub(double pad1, double pad2, double pad3) {
stackOverflowTestSub(pad1, pad2, pad3);
}
+
+ private static void testMutualRecursion() {
+ try {
+ foo(0.0, 0.0, 0.0);
+ }
+ catch (StackOverflowError soe) {
+ System.out.println("caught SOE in testMutualRecursion");
+ }
+ }
+
+ private static void foo(double pad1, double pad2, double pad3) {
+ bar(pad1, pad2, pad3);
+ }
+
+ private static void bar(double pad1, double pad2, double pad3) {
+ baz(pad1, pad2, pad3);
+ }
+
+ private static void baz(double pad1, double pad2, double pad3) {
+ qux(pad1, pad2, pad3);
+ }
+
+ private static void qux(double pad1, double pad2, double pad3) {
+ foo(pad1, pad2, pad3);
+ }
}
diff --git a/test/040-miranda/expected.txt b/test/040-miranda/expected.txt
index e22bbd974c..011be2af86 100644
--- a/test/040-miranda/expected.txt
+++ b/test/040-miranda/expected.txt
@@ -10,3 +10,5 @@ MirandaAbstract / MirandaClass2:
inInterface: true
inInterface2: 28
inAbstract: true
+Test getting miranda method via reflection:
+ caught expected NoSuchMethodException
diff --git a/test/040-miranda/src/Main.java b/test/040-miranda/src/Main.java
index 1fd8287ba0..ff5eba0a17 100644
--- a/test/040-miranda/src/Main.java
+++ b/test/040-miranda/src/Main.java
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+import java.lang.reflect.Method;
+
/**
* Miranda testing.
*/
@@ -37,5 +39,16 @@ public class Main {
System.out.println(" inInterface: " + mira2.inInterface());
System.out.println(" inInterface2: " + mira2.inInterface2());
System.out.println(" inAbstract: " + mira2.inAbstract());
+
+ System.out.println("Test getting miranda method via reflection:");
+ try {
+ Class mirandaClass = Class.forName("MirandaAbstract");
+ Method mirandaMethod = mirandaClass.getDeclaredMethod("inInterface", (Class[]) null);
+ System.out.println(" did not expect to find miranda method");
+ } catch (NoSuchMethodException nsme) {
+ System.out.println(" caught expected NoSuchMethodException");
+ } catch (Exception e) {
+ System.out.println(" caught unexpected exception " + e);
+ }
}
}
diff --git a/test/044-proxy/expected.txt b/test/044-proxy/expected.txt
index eafaf1d188..400a1619cd 100644
--- a/test/044-proxy/expected.txt
+++ b/test/044-proxy/expected.txt
@@ -42,6 +42,7 @@ Invoke public abstract java.lang.String Shapes.blob()
(no args)
--- blob
Success: method blob res=mix
+$Proxy1.getTrace null:-1
Invoke public abstract void Shapes.upChuck()
(no args)
Got expected ioobe
@@ -49,8 +50,8 @@ Invoke public abstract void Shapes.upCheck() throws java.lang.InterruptedExcepti
(no args)
Got expected ie
-Proxy interfaces: [interface Quads, interface Colors]
-Proxy methods: [public final java.lang.String $Proxy1.blob(), public final double $Proxy1.blue(int), public final R0a $Proxy1.checkMe(), public final R0aa $Proxy1.checkMe(), public final R0base $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()]
+Proxy interfaces: [interface Quads, interface Colors, interface Trace]
+Proxy methods: [public final java.lang.String $Proxy1.blob(), public final double $Proxy1.blue(int), public final R0a $Proxy1.checkMe(), public final R0aa $Proxy1.checkMe(), public final R0base $Proxy1.checkMe(), public final void $Proxy1.circle(int), public final boolean $Proxy1.equals(java.lang.Object), public final void $Proxy1.getTrace(), 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 (0) : []
Dupe threw expected exception
diff --git a/test/044-proxy/src/BasicTest.java b/test/044-proxy/src/BasicTest.java
index 46aa3feea2..ea46f49f2b 100644
--- a/test/044-proxy/src/BasicTest.java
+++ b/test/044-proxy/src/BasicTest.java
@@ -51,6 +51,8 @@ public class BasicTest {
colors.blue(777);
colors.mauve("sorry");
colors.blob();
+ Trace trace = (Trace) proxy;
+ trace.getTrace();
try {
shapes.upChuck();
@@ -96,7 +98,7 @@ public class BasicTest {
/* create the proxy class */
Class proxyClass = Proxy.getProxyClass(Shapes.class.getClassLoader(),
- new Class[] { Quads.class, Colors.class });
+ new Class[] { Quads.class, Colors.class, Trace.class });
/* create a proxy object, passing the handler object in */
Object proxy = null;
@@ -156,6 +158,10 @@ interface Colors {
public R0aa checkMe();
}
+interface Trace {
+ public void getTrace();
+}
+
/*
* Some return types.
*/
@@ -248,6 +254,20 @@ class MyInvocationHandler implements InvocationHandler {
throw new RuntimeException("huh?");
}
+ if (method.getDeclaringClass() == Trace.class) {
+ if (method.getName().equals("getTrace")) {
+ StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
+ for (int i = 0; i < stackTrace.length; i++) {
+ StackTraceElement ste = stackTrace[i];
+ if (ste.getMethodName().equals("getTrace")) {
+ System.out.println(ste.getClassName() + "." + ste.getMethodName() + " " +
+ ste.getFileName() + ":" + ste.getLineNumber());
+ }
+ }
+ return null;
+ }
+ }
+
System.out.println("Invoke " + method);
if (args == null || args.length == 0) {
System.out.println(" (no args)");
diff --git a/test/JniTest/JniTest.java b/test/JniTest/JniTest.java
index 7014ef9334..9194da581f 100644
--- a/test/JniTest/JniTest.java
+++ b/test/JniTest/JniTest.java
@@ -14,15 +14,30 @@
* limitations under the License.
*/
+import java.lang.reflect.Method;
+
class JniTest {
public static void main(String[] args) {
System.loadLibrary("arttest");
testFindClassOnAttachedNativeThread();
+ testFindFieldOnAttachedNativeThread();
testCallStaticVoidMethodOnSubClass();
+ testGetMirandaMethod();
}
private static native void testFindClassOnAttachedNativeThread();
+ private static boolean testFindFieldOnAttachedNativeThreadField;
+
+ private static void testFindFieldOnAttachedNativeThread() {
+ testFindFieldOnAttachedNativeThreadNative();
+ if (!testFindFieldOnAttachedNativeThreadField) {
+ throw new AssertionError();
+ }
+ }
+
+ private static native void testFindFieldOnAttachedNativeThreadNative();
+
private static void testCallStaticVoidMethodOnSubClass() {
testCallStaticVoidMethodOnSubClassNative();
if (!testCallStaticVoidMethodOnSubClass_SuperClass.executed) {
@@ -42,4 +57,23 @@ class JniTest {
private static class testCallStaticVoidMethodOnSubClass_SubClass
extends testCallStaticVoidMethodOnSubClass_SuperClass {
}
+
+ private static native Method testGetMirandaMethodNative();
+
+ private static void testGetMirandaMethod() {
+ Method m = testGetMirandaMethodNative();
+ if (m.getDeclaringClass() != testGetMirandaMethod_MirandaInterface.class) {
+ throw new AssertionError();
+ }
+ }
+
+ private static abstract class testGetMirandaMethod_MirandaAbstract implements testGetMirandaMethod_MirandaInterface {
+ public boolean inAbstract() {
+ return true;
+ }
+ }
+
+ private static interface testGetMirandaMethod_MirandaInterface {
+ public boolean inInterface();
+ }
}
diff --git a/test/JniTest/jni_test.cc b/test/JniTest/jni_test.cc
index 72a3309d9d..d15e180c02 100644
--- a/test/JniTest/jni_test.cc
+++ b/test/JniTest/jni_test.cc
@@ -67,6 +67,42 @@ extern "C" JNIEXPORT void JNICALL Java_JniTest_testFindClassOnAttachedNativeThre
assert(pthread_join_result == 0);
}
+static void* testFindFieldOnAttachedNativeThread(void*) {
+ assert(jvm != NULL);
+
+ JNIEnv* env = NULL;
+ JavaVMAttachArgs args = { JNI_VERSION_1_6, __FUNCTION__, NULL };
+ int attach_result = jvm->AttachCurrentThread(&env, &args);
+ assert(attach_result == 0);
+
+ jclass clazz = env->FindClass("JniTest");
+ assert(clazz != NULL);
+ assert(!env->ExceptionCheck());
+
+ jfieldID field = env->GetStaticFieldID(clazz, "testFindFieldOnAttachedNativeThreadField", "Z");
+ assert(field != NULL);
+ assert(!env->ExceptionCheck());
+
+ env->SetStaticBooleanField(clazz, field, JNI_TRUE);
+
+ int detach_result = jvm->DetachCurrentThread();
+ assert(detach_result == 0);
+ return NULL;
+}
+
+extern "C" JNIEXPORT void JNICALL Java_JniTest_testFindFieldOnAttachedNativeThreadNative(JNIEnv*,
+ jclass) {
+ pthread_t pthread;
+ int pthread_create_result = pthread_create(&pthread,
+ NULL,
+ testFindFieldOnAttachedNativeThread,
+ NULL);
+ assert(pthread_create_result == 0);
+ int pthread_join_result = pthread_join(pthread, NULL);
+ assert(pthread_join_result == 0);
+}
+
+
// http://b/11243757
extern "C" JNIEXPORT void JNICALL Java_JniTest_testCallStaticVoidMethodOnSubClassNative(JNIEnv* env,
jclass) {
@@ -81,3 +117,11 @@ extern "C" JNIEXPORT void JNICALL Java_JniTest_testCallStaticVoidMethodOnSubClas
env->CallStaticVoidMethod(sub_class, execute);
}
+
+extern "C" JNIEXPORT jobject JNICALL Java_JniTest_testGetMirandaMethodNative(JNIEnv* env, jclass) {
+ jclass abstract_class = env->FindClass("JniTest$testGetMirandaMethod_MirandaAbstract");
+ assert(abstract_class != NULL);
+ jmethodID miranda_method = env->GetMethodID(abstract_class, "inInterface", "()Z");
+ assert(miranda_method != NULL);
+ return env->ToReflectedMethod(abstract_class, miranda_method, JNI_FALSE);
+}