Merge "Use libnativehelper's existing code for creating a String[]." into dalvik-dev
diff --git a/src/calling_convention_arm.cc b/src/calling_convention_arm.cc
index 0300ad1..743445d 100644
--- a/src/calling_convention_arm.cc
+++ b/src/calling_convention_arm.cc
@@ -31,10 +31,7 @@
// Managed runtime calling convention
bool ManagedRuntimeCallingConvention::IsCurrentParamInRegister() {
- if (itr_slots_ < 3) {
- return true;
- }
- return false; // everything else on the stack
+ return itr_slots_ < 3;
}
bool ManagedRuntimeCallingConvention::IsCurrentParamOnStack() {
@@ -67,8 +64,7 @@
FrameOffset ManagedRuntimeCallingConvention::CurrentParamStackOffset() {
CHECK_GE(itr_slots_, 3u);
- return FrameOffset(displacement_.Int32Value() +
- ((itr_slots_ - 3) * kPointerSize));
+ return FrameOffset(displacement_.Int32Value() + (itr_slots_ * kPointerSize));
}
// JNI calling convention
diff --git a/src/calling_convention_x86.cc b/src/calling_convention_x86.cc
index 9420849..ed95eb0 100644
--- a/src/calling_convention_x86.cc
+++ b/src/calling_convention_x86.cc
@@ -43,7 +43,9 @@
}
FrameOffset ManagedRuntimeCallingConvention::CurrentParamStackOffset() {
- return FrameOffset(displacement_.Int32Value() + (itr_slots_ * kPointerSize));
+ return FrameOffset(displacement_.Int32Value() + // displacement
+ kPointerSize + // Method*
+ (itr_slots_ * kPointerSize)); // offset into in args
}
// JNI calling convention
diff --git a/src/indirect_reference_table.cc b/src/indirect_reference_table.cc
index b30ce53..ec52cc6 100644
--- a/src/indirect_reference_table.cc
+++ b/src/indirect_reference_table.cc
@@ -16,6 +16,7 @@
#include "indirect_reference_table.h"
#include "reference_table.h"
+#include "utils.h"
#include <cstdlib>
@@ -82,7 +83,8 @@
size_t topIndex = segmentState.parts.topIndex;
DCHECK(obj != NULL);
- //DCHECK(dvmIsHeapAddress(obj));
+ // TODO: stronger sanity check on the object (such as in heap)
+ DCHECK(IsAligned(reinterpret_cast<intptr_t>(obj), 8));
DCHECK(table_ != NULL);
DCHECK_LE(alloc_entries_, max_entries_);
DCHECK_GE(segmentState.parts.numHoles, prevState.parts.numHoles);
diff --git a/src/jni_compiler.cc b/src/jni_compiler.cc
index 440dda5..077e7bb 100644
--- a/src/jni_compiler.cc
+++ b/src/jni_compiler.cc
@@ -59,7 +59,7 @@
// Check handle offset is within frame
CHECK_LT(handle_offset.Uint32Value(), frame_size);
jni_asm->LoadRef(jni_conv.InterproceduralScratchRegister(),
- mr_conv.MethodRegister(), Method::ClassOffset());
+ mr_conv.MethodRegister(), Method::DeclaringClassOffset());
jni_asm->ValidateRef(jni_conv.InterproceduralScratchRegister(), false);
jni_asm->StoreRef(handle_offset, jni_conv.InterproceduralScratchRegister());
jni_conv.Next(); // handlerized so move to next argument
diff --git a/src/jni_compiler_test.cc b/src/jni_compiler_test.cc
index 854df88..39ba6ed 100644
--- a/src/jni_compiler_test.cc
+++ b/src/jni_compiler_test.cc
@@ -6,7 +6,9 @@
#include "class_linker.h"
#include "common_test.h"
#include "dex_file.h"
+#include "indirect_reference_table.h"
#include "jni_compiler.h"
+#include "jni_internal.h"
#include "mem_map.h"
#include "runtime.h"
#include "scoped_ptr.h"
@@ -19,143 +21,173 @@
protected:
virtual void SetUp() {
CommonTest::SetUp();
- // Create thunk code that performs the native to managed transition
- thunk_code_.reset(MemMap::Map(kPageSize, PROT_READ | PROT_WRITE | PROT_EXEC));
- CHECK(thunk_code_ != NULL);
- Assembler thk_asm;
- // TODO: shouldn't have machine specific code in a general purpose file
-#if defined(__i386__)
- thk_asm.pushl(EDI); // preserve EDI
- thk_asm.movl(EAX, Address(ESP, 8)); // EAX = method->GetCode()
- thk_asm.movl(EDI, Address(ESP, 12)); // EDI = method
- thk_asm.pushl(Immediate(0)); // push pad
- thk_asm.pushl(Immediate(0)); // push pad
- thk_asm.pushl(Address(ESP, 44)); // push pad or jlong high
- thk_asm.pushl(Address(ESP, 44)); // push jint or jlong low
- thk_asm.pushl(Address(ESP, 44)); // push jint or jlong high
- thk_asm.pushl(Address(ESP, 44)); // push jint or jlong low
- thk_asm.pushl(Address(ESP, 44)); // push jobject
- thk_asm.call(EAX); // Continue in method->GetCode()
- thk_asm.addl(ESP, Immediate(28)); // pop arguments
- thk_asm.popl(EDI); // restore EDI
- thk_asm.ret();
-#elif defined(__arm__)
- thk_asm.AddConstant(SP, -32); // Build frame
- thk_asm.StoreToOffset(kStoreWord, LR, SP, 28); // Spill link register
- thk_asm.StoreToOffset(kStoreWord, R9, SP, 24); // Spill R9
- thk_asm.mov(R12, ShifterOperand(R0)); // R12 = method->GetCode()
- thk_asm.mov(R0, ShifterOperand(R1)); // R0 = method
- thk_asm.mov(R9, ShifterOperand(R2)); // R9 = Thread::Current()
- thk_asm.mov(R1, ShifterOperand(R3)); // R1 = arg1 (jint/jlong low)
- thk_asm.LoadFromOffset(kLoadWord, R3, SP, 44); // R3 = arg5 (pad/jlong high)
- thk_asm.StoreToOffset(kStoreWord, R3, SP, 4);
- thk_asm.LoadFromOffset(kLoadWord, R3, SP, 40); // R3 = arg4 (jint/jlong low)
- thk_asm.StoreToOffset(kStoreWord, R3, SP, 0);
- thk_asm.LoadFromOffset(kLoadWord, R3, SP, 36); // R3 = arg3 (jint/jlong high)
- thk_asm.LoadFromOffset(kLoadWord, R2, SP, 32); // R2 = arg2 (jint/jlong high)
- thk_asm.blx(R12); // Branch and link R12
- thk_asm.LoadFromOffset(kLoadWord, LR, SP, 28); // Fill link register
- thk_asm.LoadFromOffset(kLoadWord, R9, SP, 24); // Fill R9
- thk_asm.AddConstant(SP, 32); // Remove frame
- thk_asm.mov(PC, ShifterOperand(LR)); // Return
-#else
-#error Unimplemented
-#endif
- size_t cs = thk_asm.CodeSize();
- MemoryRegion code(thunk_code_->GetAddress(), cs);
- thk_asm.FinalizeInstructions(code);
- thunk_entry1_ = reinterpret_cast<jint (*)(const void*, art::Method*,
- Thread*, jobject, jint, jint,
- jint)
- >(code.pointer());
- thunk_entry2_ = reinterpret_cast<jdouble (*)(const void*, art::Method*,
- Thread*, jobject, jdouble,
- jdouble)
- >(code.pointer());
+ dex_.reset(OpenDexFileBase64(kMyClassNativesDex));
+ class_loader_ = AllocPathClassLoader(dex_.get());
}
- virtual void TearDown() {
- // Release thunk code
- CHECK(runtime_->DetachCurrentThread());
+ void SetupForTest(bool direct, const char* method_name,
+ const char* method_sig, void* native_fnptr) {
+ const char* class_name = "LMyClass;";
+ Class* klass = class_linker_->FindClass(class_name, class_loader_);
+ ASSERT_TRUE(klass != NULL);
+
+ Method* method;
+ if (direct) {
+ method = klass->FindDirectMethod(method_name, method_sig);
+ } else {
+ method = klass->FindVirtualMethod(method_name, method_sig);
+ }
+ ASSERT_TRUE(method != NULL);
+
+ // Compile the native method
+ jni_compiler.Compile(&jni_asm, method);
+
+ env_ = Thread::Current()->GetJniEnv();
+
+ // TODO: when we support class loaders - env->FindClass(class_name);
+ IndirectReferenceTable& locals = reinterpret_cast<JNIEnvExt*>(env_)->locals;
+ uint32_t cookie = IRT_FIRST_SEGMENT; // TODO
+ IndirectRef klass_ref = locals.Add(cookie, klass);
+ jklass_ = reinterpret_cast<jclass>(klass_ref);
+ if (direct) {
+ jmethod_ = env_->GetStaticMethodID(jklass_, method_name, method_sig);
+ } else {
+ jmethod_ = env_->GetMethodID(jklass_, method_name, method_sig);
+ }
+ ASSERT_TRUE(jmethod_ != NULL);
+
+ JNINativeMethod methods[] = {{method_name, method_sig, native_fnptr}};
+ ASSERT_EQ(JNI_OK, env_->RegisterNatives(jklass_, methods, 1));
+
+ jmethodID constructor = env_->GetMethodID(jklass_, "<init>", "()V");
+ jobj_ = env_->NewObject(jklass_, constructor);
+ ASSERT_TRUE(jobj_ != NULL);
}
- // Run generated code associated with method passing and returning int size
- // arguments
- jvalue RunMethod(Method* method, jvalue a, jvalue b, jvalue c, jvalue d) {
- jvalue result;
- // sanity checks
- EXPECT_NE(static_cast<void*>(NULL), method->GetCode());
- EXPECT_EQ(0u, Thread::Current()->NumShbHandles());
- EXPECT_EQ(Thread::kRunnable, Thread::Current()->GetState());
- // perform call
- result.i = (*thunk_entry1_)(method->GetCode(), method, Thread::Current(),
- a.l, b.i, c.i, d.i);
- // sanity check post-call
- EXPECT_EQ(0u, Thread::Current()->NumShbHandles());
- EXPECT_EQ(Thread::kRunnable, Thread::Current()->GetState());
- return result;
- }
-
- // Run generated code associated with method passing and returning double size
- // arguments
- jvalue RunMethodD(Method* method, jvalue a, jvalue b, jvalue c) {
- jvalue result;
- // sanity checks
- EXPECT_NE(static_cast<void*>(NULL), method->GetCode());
- EXPECT_EQ(0u, Thread::Current()->NumShbHandles());
- EXPECT_EQ(Thread::kRunnable, Thread::Current()->GetState());
- // perform call
- result.d = (*thunk_entry2_)(method->GetCode(), method, Thread::Current(),
- a.l, b.d, c.d);
- // sanity check post-call
- EXPECT_EQ(0u, Thread::Current()->NumShbHandles());
- EXPECT_EQ(Thread::kRunnable, Thread::Current()->GetState());
- return result;
- }
-
- scoped_ptr<MemMap> thunk_code_;
- jint (*thunk_entry1_)(const void*, Method*, Thread*, jobject, jint, jint,
- jint);
- jdouble (*thunk_entry2_)(const void*, Method*, Thread*, jobject, jdouble,
- jdouble);
+ public:
+ static jclass jklass_;
+ static jobject jobj_;
+ protected:
+ scoped_ptr<DexFile> dex_;
+ PathClassLoader* class_loader_;
+ Assembler jni_asm;
+ JniCompiler jni_compiler;
+ JNIEnv* env_;
+ jmethodID jmethod_;
};
+jclass JniCompilerTest::jklass_;
+jobject JniCompilerTest::jobj_;
+
int gJava_MyClass_foo_calls = 0;
-void Java_MyClass_foo(JNIEnv*, jobject) {
+void Java_MyClass_foo(JNIEnv* env, jobject thisObj) {
EXPECT_EQ(1u, Thread::Current()->NumShbHandles());
EXPECT_EQ(Thread::kNative, Thread::Current()->GetState());
+ EXPECT_EQ(Thread::Current()->GetJniEnv(), env);
+ EXPECT_TRUE(thisObj != NULL);
+ // TODO: check JNIEnv and thisObj are sane
+ // EXPECT_TRUE(env->IsInstanceOf(thisObj, JniCompilerTest::jklass_));
gJava_MyClass_foo_calls++;
}
+TEST_F(JniCompilerTest, CompileAndRunNoArgMethod) {
+ SetupForTest(false, "foo", "()V", reinterpret_cast<void*>(&Java_MyClass_foo));
+
+ EXPECT_EQ(0, gJava_MyClass_foo_calls);
+ env_->CallNonvirtualVoidMethod(jobj_, jklass_, jmethod_);
+ EXPECT_EQ(1, gJava_MyClass_foo_calls);
+ env_->CallNonvirtualVoidMethod(jobj_, jklass_, jmethod_);
+ EXPECT_EQ(2, gJava_MyClass_foo_calls);
+}
+
int gJava_MyClass_fooI_calls = 0;
-jint Java_MyClass_fooI(JNIEnv*, jobject, jint x) {
+jint Java_MyClass_fooI(JNIEnv* env, jobject thisObj, jint x) {
EXPECT_EQ(1u, Thread::Current()->NumShbHandles());
EXPECT_EQ(Thread::kNative, Thread::Current()->GetState());
+ EXPECT_EQ(Thread::Current()->GetJniEnv(), env);
+ EXPECT_TRUE(thisObj != NULL);
+ // TODO: check JNIEnv and thisObj are sane
+ // EXPECT_TRUE(env->IsInstanceOf(thisObj, JniCompilerTest::jklass_));
gJava_MyClass_fooI_calls++;
return x;
}
+TEST_F(JniCompilerTest, CompileAndRunIntMethod) {
+ SetupForTest(false, "fooI", "(I)I",
+ reinterpret_cast<void*>(&Java_MyClass_fooI));
+
+ EXPECT_EQ(0, gJava_MyClass_fooI_calls);
+ jint result = env_->CallNonvirtualIntMethod(jobj_, jklass_, jmethod_, 42);
+ EXPECT_EQ(42, result);
+ EXPECT_EQ(1, gJava_MyClass_fooI_calls);
+ result = env_->CallNonvirtualIntMethod(jobj_, jklass_, jmethod_, 0xCAFED00D);
+ EXPECT_EQ(static_cast<jint>(0xCAFED00D), result);
+ EXPECT_EQ(2, gJava_MyClass_fooI_calls);
+}
+
int gJava_MyClass_fooII_calls = 0;
-jint Java_MyClass_fooII(JNIEnv*, jobject, jint x, jint y) {
+jint Java_MyClass_fooII(JNIEnv* env, jobject thisObj, jint x, jint y) {
EXPECT_EQ(1u, Thread::Current()->NumShbHandles());
EXPECT_EQ(Thread::kNative, Thread::Current()->GetState());
+ EXPECT_EQ(Thread::Current()->GetJniEnv(), env);
+ EXPECT_TRUE(thisObj != NULL);
+ // TODO: check JNIEnv and thisObj are sane
+ // EXPECT_TRUE(env->IsInstanceOf(thisObj, JniCompilerTest::jklass_));
gJava_MyClass_fooII_calls++;
return x - y; // non-commutative operator
}
+TEST_F(JniCompilerTest, CompileAndRunIntIntMethod) {
+ SetupForTest(false, "fooII", "(II)I",
+ reinterpret_cast<void*>(&Java_MyClass_fooII));
+
+ EXPECT_EQ(0, gJava_MyClass_fooII_calls);
+ jint result = env_->CallNonvirtualIntMethod(jobj_, jklass_, jmethod_, 99, 10);
+ EXPECT_EQ(99 - 10, result);
+ EXPECT_EQ(1, gJava_MyClass_fooII_calls);
+ result = env_->CallNonvirtualIntMethod(jobj_, jklass_, jmethod_, 0xCAFEBABE,
+ 0xCAFED00D);
+ EXPECT_EQ(static_cast<jint>(0xCAFEBABE - 0xCAFED00D), result);
+ EXPECT_EQ(2, gJava_MyClass_fooII_calls);
+}
+
int gJava_MyClass_fooDD_calls = 0;
-jdouble Java_MyClass_fooDD(JNIEnv*, jobject, jdouble x, jdouble y) {
+jdouble Java_MyClass_fooDD(JNIEnv* env, jobject thisObj, jdouble x, jdouble y) {
EXPECT_EQ(1u, Thread::Current()->NumShbHandles());
EXPECT_EQ(Thread::kNative, Thread::Current()->GetState());
+ EXPECT_EQ(Thread::Current()->GetJniEnv(), env);
+ EXPECT_TRUE(thisObj != NULL);
+ // TODO: check JNIEnv and thisObj are sane
+ // EXPECT_TRUE(env->IsInstanceOf(thisObj, JniCompilerTest::jklass_));
gJava_MyClass_fooDD_calls++;
return x - y; // non-commutative operator
}
+TEST_F(JniCompilerTest, CompileAndRunDoubleDoubleMethod) {
+ SetupForTest(false, "fooDD", "(DD)D",
+ reinterpret_cast<void*>(&Java_MyClass_fooDD));
+
+ EXPECT_EQ(0, gJava_MyClass_fooDD_calls);
+ jdouble result = env_->CallNonvirtualDoubleMethod(jobj_, jklass_, jmethod_,
+ 99.0, 10.0);
+ EXPECT_EQ(99.0 - 10.0, result);
+ EXPECT_EQ(1, gJava_MyClass_fooDD_calls);
+ jdouble a = 3.14159265358979323846;
+ jdouble b = 0.69314718055994530942;
+ result = env_->CallNonvirtualDoubleMethod(jobj_, jklass_, jmethod_, a, b);
+ EXPECT_EQ(a - b, result);
+ EXPECT_EQ(2, gJava_MyClass_fooDD_calls);
+}
+
int gJava_MyClass_fooIOO_calls = 0;
-jobject Java_MyClass_fooIOO(JNIEnv*, jobject thisObject, jint x, jobject y,
+jobject Java_MyClass_fooIOO(JNIEnv* env, jobject thisObj, jint x, jobject y,
jobject z) {
EXPECT_EQ(3u, Thread::Current()->NumShbHandles());
EXPECT_EQ(Thread::kNative, Thread::Current()->GetState());
+ EXPECT_EQ(Thread::Current()->GetJniEnv(), env);
+ EXPECT_TRUE(thisObj != NULL);
+ // TODO: check JNIEnv and thisObj are sane
+ // EXPECT_TRUE(env->IsInstanceOf(thisObj, JniCompilerTest::jklass_));
gJava_MyClass_fooIOO_calls++;
switch (x) {
case 1:
@@ -163,16 +195,50 @@
case 2:
return z;
default:
- return thisObject;
+ return thisObj;
}
}
+TEST_F(JniCompilerTest, CompileAndRunIntObjectObjectMethod) {
+ SetupForTest(false, "fooIOO",
+ "(ILjava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;",
+ reinterpret_cast<void*>(&Java_MyClass_fooIOO));
+
+ EXPECT_EQ(0, gJava_MyClass_fooIOO_calls);
+ jobject result = env_->CallNonvirtualObjectMethod(jobj_, jklass_, jmethod_, 0, NULL, NULL);
+ EXPECT_TRUE(env_->IsSameObject(jobj_, result));
+ EXPECT_EQ(1, gJava_MyClass_fooIOO_calls);
+
+ result = env_->CallNonvirtualObjectMethod(jobj_, jklass_, jmethod_, 0, NULL, jklass_);
+ EXPECT_TRUE(env_->IsSameObject(jobj_, result));
+ EXPECT_EQ(2, gJava_MyClass_fooIOO_calls);
+ result = env_->CallNonvirtualObjectMethod(jobj_, jklass_, jmethod_, 1, NULL, jklass_);
+ EXPECT_TRUE(env_->IsSameObject(NULL, result));
+ EXPECT_EQ(3, gJava_MyClass_fooIOO_calls);
+ result = env_->CallNonvirtualObjectMethod(jobj_, jklass_, jmethod_, 2, NULL, jklass_);
+ EXPECT_TRUE(env_->IsSameObject(jklass_, result));
+ EXPECT_EQ(4, gJava_MyClass_fooIOO_calls);
+
+ result = env_->CallNonvirtualObjectMethod(jobj_, jklass_, jmethod_, 0, jklass_, NULL);
+ EXPECT_TRUE(env_->IsSameObject(jobj_, result));
+ EXPECT_EQ(5, gJava_MyClass_fooIOO_calls);
+ result = env_->CallNonvirtualObjectMethod(jobj_, jklass_, jmethod_, 1, jklass_, NULL);
+ EXPECT_TRUE(env_->IsSameObject(jklass_, result));
+ EXPECT_EQ(6, gJava_MyClass_fooIOO_calls);
+ result = env_->CallNonvirtualObjectMethod(jobj_, jklass_, jmethod_, 2, jklass_, NULL);
+ EXPECT_TRUE(env_->IsSameObject(NULL, result));
+ EXPECT_EQ(7, gJava_MyClass_fooIOO_calls);
+}
+
int gJava_MyClass_fooSIOO_calls = 0;
jobject Java_MyClass_fooSIOO(JNIEnv* env, jclass klass, jint x, jobject y,
jobject z) {
- EXPECT_EQ(Thread::Current()->GetJniEnv(), env);
EXPECT_EQ(3u, Thread::Current()->NumShbHandles());
EXPECT_EQ(Thread::kNative, Thread::Current()->GetState());
+ EXPECT_EQ(Thread::Current()->GetJniEnv(), env);
+ EXPECT_TRUE(klass != NULL);
+ // TODO: check JNIEnv and klass are sane
+ // EXPECT_TRUE(env->IsInstanceOf(JniCompilerTest::jobj_, klass));
gJava_MyClass_fooSIOO_calls++;
switch (x) {
case 1:
@@ -184,11 +250,47 @@
}
}
+
+TEST_F(JniCompilerTest, CompileAndRunStaticIntObjectObjectMethod) {
+ SetupForTest(true, "fooSIOO",
+ "(ILjava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;",
+ reinterpret_cast<void*>(&Java_MyClass_fooSIOO));
+
+ EXPECT_EQ(0, gJava_MyClass_fooSIOO_calls);
+ jobject result = env_->CallStaticObjectMethod(jklass_, jmethod_, 0, NULL, NULL);
+ EXPECT_TRUE(env_->IsSameObject(jklass_, result));
+ EXPECT_EQ(1, gJava_MyClass_fooSIOO_calls);
+
+ result = env_->CallStaticObjectMethod(jklass_, jmethod_, 0, NULL, jobj_);
+ EXPECT_TRUE(env_->IsSameObject(jklass_, result));
+ EXPECT_EQ(2, gJava_MyClass_fooSIOO_calls);
+ result = env_->CallStaticObjectMethod(jklass_, jmethod_, 1, NULL, jobj_);
+ EXPECT_TRUE(env_->IsSameObject(NULL, result));
+ EXPECT_EQ(3, gJava_MyClass_fooSIOO_calls);
+ result = env_->CallStaticObjectMethod(jklass_, jmethod_, 2, NULL, jobj_);
+ EXPECT_TRUE(env_->IsSameObject(jobj_, result));
+ EXPECT_EQ(4, gJava_MyClass_fooSIOO_calls);
+
+ result = env_->CallStaticObjectMethod(jklass_, jmethod_, 0, jobj_, NULL);
+ EXPECT_TRUE(env_->IsSameObject(jklass_, result));
+ EXPECT_EQ(5, gJava_MyClass_fooSIOO_calls);
+ result = env_->CallStaticObjectMethod(jklass_, jmethod_, 1, jobj_, NULL);
+ EXPECT_TRUE(env_->IsSameObject(jobj_, result));
+ EXPECT_EQ(6, gJava_MyClass_fooSIOO_calls);
+ result = env_->CallStaticObjectMethod(jklass_, jmethod_, 2, jobj_, NULL);
+ EXPECT_TRUE(env_->IsSameObject(NULL, result));
+ EXPECT_EQ(7, gJava_MyClass_fooSIOO_calls);
+}
+
int gJava_MyClass_fooSSIOO_calls = 0;
-jobject Java_MyClass_fooSSIOO(JNIEnv*, jclass klass, jint x, jobject y,
+jobject Java_MyClass_fooSSIOO(JNIEnv* env, jclass klass, jint x, jobject y,
jobject z) {
EXPECT_EQ(3u, Thread::Current()->NumShbHandles());
EXPECT_EQ(Thread::kNative, Thread::Current()->GetState());
+ EXPECT_EQ(Thread::Current()->GetJniEnv(), env);
+ EXPECT_TRUE(klass != NULL);
+ // TODO: check JNIEnv and klass are sane
+ // EXPECT_TRUE(env->IsInstanceOf(JniCompilerTest::jobj_, klass));
gJava_MyClass_fooSSIOO_calls++;
switch (x) {
case 1:
@@ -200,307 +302,34 @@
}
}
-TEST_F(JniCompilerTest, CompileAndRunNoArgMethod) {
- scoped_ptr<DexFile> dex(OpenDexFileBase64(kMyClassNativesDex));
- PathClassLoader* class_loader = AllocPathClassLoader(dex.get());
-
- Class* klass = class_linker_->FindClass("LMyClass;", class_loader);
- ASSERT_TRUE(klass != NULL);
-
- Method* method = klass->FindVirtualMethod("foo", "()V");
- ASSERT_TRUE(method != NULL);
-
- Assembler jni_asm;
- JniCompiler jni_compiler;
- jni_compiler.Compile(&jni_asm, method);
-
- // TODO: should really use JNIEnv to RegisterNative, but missing a
- // complete story on this, so hack the RegisterNative below
- // JNIEnv* env = Thread::Current()->GetJniEnv();
- // JNINativeMethod methods[] = {{"foo", "()V", (void*)&Java_MyClass_foo}};
- method->RegisterNative(reinterpret_cast<void*>(&Java_MyClass_foo));
-
- jvalue a;
- a.l = (jobject)NULL;
- gJava_MyClass_foo_calls = 0;
- RunMethod(method, a, a, a, a);
- EXPECT_EQ(1, gJava_MyClass_foo_calls);
- RunMethod(method, a, a, a, a);
- EXPECT_EQ(2, gJava_MyClass_foo_calls);
-}
-
-TEST_F(JniCompilerTest, CompileAndRunIntMethod) {
- scoped_ptr<DexFile> dex(OpenDexFileBase64(kMyClassNativesDex));
- PathClassLoader* class_loader = AllocPathClassLoader(dex.get());
-
- Class* klass = class_linker_->FindClass("LMyClass;", class_loader);
- ASSERT_TRUE(klass != NULL);
-
- Method* method = klass->FindVirtualMethod("fooI", "(I)I");
- ASSERT_TRUE(method != NULL);
-
- Assembler jni_asm;
- JniCompiler jni_compiler;
- jni_compiler.Compile(&jni_asm, method);
-
- // TODO: should really use JNIEnv to RegisterNative, but missing a
- // complete story on this, so hack the RegisterNative below
- method->RegisterNative(reinterpret_cast<void*>(&Java_MyClass_fooI));
-
- jvalue a, b, c;
- a.l = (jobject)NULL;
- b.i = 42;
- EXPECT_EQ(0, gJava_MyClass_fooI_calls);
- c = RunMethod(method, a, b, a, a);
- ASSERT_EQ(42, c.i);
- EXPECT_EQ(1, gJava_MyClass_fooI_calls);
- b.i = 0xCAFED00D;
- c = RunMethod(method, a, b, a, a);
- ASSERT_EQ((jint)0xCAFED00D, c.i);
- EXPECT_EQ(2, gJava_MyClass_fooI_calls);
-}
-
-TEST_F(JniCompilerTest, CompileAndRunIntIntMethod) {
- scoped_ptr<DexFile> dex(OpenDexFileBase64(kMyClassNativesDex));
- PathClassLoader* class_loader = AllocPathClassLoader(dex.get());
-
- Class* klass = class_linker_->FindClass("LMyClass;", class_loader);
- ASSERT_TRUE(klass != NULL);
-
- Method* method = klass->FindVirtualMethod("fooII", "(II)I");
- ASSERT_TRUE(method != NULL);
-
- Assembler jni_asm;
- JniCompiler jni_compiler;
- jni_compiler.Compile(&jni_asm, method);
-
- // TODO: should really use JNIEnv to RegisterNative, but missing a
- // complete story on this, so hack the RegisterNative below
- method->RegisterNative(reinterpret_cast<void*>(&Java_MyClass_fooII));
-
- jvalue a, b, c, d;
- a.l = (jobject)NULL;
- b.i = 99;
- c.i = 10;
- EXPECT_EQ(0, gJava_MyClass_fooII_calls);
- d = RunMethod(method, a, b, c, a);
- ASSERT_EQ(99 - 10, d.i);
- EXPECT_EQ(1, gJava_MyClass_fooII_calls);
- b.i = 0xCAFEBABE;
- c.i = 0xCAFED00D;
- d = RunMethod(method, a, b, c, a);
- ASSERT_EQ((jint)(0xCAFEBABE - 0xCAFED00D), d.i);
- EXPECT_EQ(2, gJava_MyClass_fooII_calls);
-}
-
-
-TEST_F(JniCompilerTest, CompileAndRunDoubleDoubleMethod) {
- scoped_ptr<DexFile> dex(OpenDexFileBase64(kMyClassNativesDex));
- PathClassLoader* class_loader = AllocPathClassLoader(dex.get());
-
- Class* klass = class_linker_->FindClass("LMyClass;", class_loader);
- ASSERT_TRUE(klass != NULL);
-
- Method* method = klass->FindVirtualMethod("fooDD", "(DD)D");
- ASSERT_TRUE(method != NULL);
-
- Assembler jni_asm;
- JniCompiler jni_compiler;
- jni_compiler.Compile(&jni_asm, method);
-
- // TODO: should really use JNIEnv to RegisterNative, but missing a
- // complete story on this, so hack the RegisterNative below
- method->RegisterNative(reinterpret_cast<void*>(&Java_MyClass_fooDD));
-
- jvalue a, b, c, d;
- a.l = (jobject)NULL;
- b.d = 99;
- c.d = 10;
- EXPECT_EQ(0, gJava_MyClass_fooDD_calls);
- d = RunMethodD(method, a, b, c);
- ASSERT_EQ(b.d - c.d, d.d);
- EXPECT_EQ(1, gJava_MyClass_fooDD_calls);
- b.d = 3.14159265358979323846;
- c.d = 0.69314718055994530942;
- d = RunMethodD(method, a, b, c);
- ASSERT_EQ(b.d - c.d, d.d);
- EXPECT_EQ(2, gJava_MyClass_fooDD_calls);
-}
-
-TEST_F(JniCompilerTest, CompileAndRunIntObjectObjectMethod) {
- scoped_ptr<DexFile> dex(OpenDexFileBase64(kMyClassNativesDex));
- PathClassLoader* class_loader = AllocPathClassLoader(dex.get());
-
- Class* klass = class_linker_->FindClass("LMyClass;", class_loader);
- ASSERT_TRUE(klass != NULL);
-
- Method* method = klass->FindVirtualMethod(
- "fooIOO",
- "(ILjava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
- ASSERT_TRUE(method != NULL);
-
- Assembler jni_asm;
- JniCompiler jni_compiler;
- jni_compiler.Compile(&jni_asm, method);
-
- // TODO: should really use JNIEnv to RegisterNative, but missing a
- // complete story on this, so hack the RegisterNative below
- method->RegisterNative(reinterpret_cast<void*>(&Java_MyClass_fooIOO));
-
- jvalue a, b, c, d, e;
- a.l = (jobject)NULL;
- b.i = 0;
- c.l = (jobject)NULL;
- d.l = (jobject)NULL;
- EXPECT_EQ(0, gJava_MyClass_fooIOO_calls);
- e = RunMethod(method, a, b, c, d);
- ASSERT_EQ((jobject)NULL, e.l);
- EXPECT_EQ(1, gJava_MyClass_fooIOO_calls);
- a.l = (jobject)8;
- b.i = 0;
- c.l = (jobject)NULL;
- d.l = (jobject)16;
- e = RunMethod(method, a, b, c, d);
- ASSERT_EQ((jobject)8, e.l);
- EXPECT_EQ(2, gJava_MyClass_fooIOO_calls);
- b.i = 1;
- e = RunMethod(method, a, b, c, d);
- ASSERT_EQ((jobject)NULL, e.l);
- EXPECT_EQ(3, gJava_MyClass_fooIOO_calls);
- b.i = 2;
- e = RunMethod(method, a, b, c, d);
- ASSERT_EQ((jobject)16, e.l);
- EXPECT_EQ(4, gJava_MyClass_fooIOO_calls);
- a.l = (jobject)8;
- b.i = 0;
- c.l = (jobject)16;
- d.l = (jobject)NULL;
- e = RunMethod(method, a, b, c, d);
- ASSERT_EQ((jobject)8, e.l);
- EXPECT_EQ(5, gJava_MyClass_fooIOO_calls);
- b.i = 1;
- e = RunMethod(method, a, b, c, d);
- ASSERT_EQ((jobject)16, e.l);
- EXPECT_EQ(6, gJava_MyClass_fooIOO_calls);
- b.i = 2;
- e = RunMethod(method, a, b, c, d);
- ASSERT_EQ((jobject)NULL, e.l);
- EXPECT_EQ(7, gJava_MyClass_fooIOO_calls);
-}
-
-TEST_F(JniCompilerTest, CompileAndRunStaticIntObjectObjectMethod) {
- scoped_ptr<DexFile> dex(OpenDexFileBase64(kMyClassNativesDex));
- PathClassLoader* class_loader = AllocPathClassLoader(dex.get());
-
- Class* klass = class_linker_->FindClass("LMyClass;", class_loader);
- ASSERT_TRUE(klass != NULL);
-
- Method* method = klass->FindDirectMethod(
- "fooSIOO",
- "(ILjava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
- ASSERT_TRUE(method != NULL);
-
- Assembler jni_asm;
- JniCompiler jni_compiler;
- jni_compiler.Compile(&jni_asm, method);
-
- // TODO: should really use JNIEnv to RegisterNative, but missing a
- // complete story on this, so hack the RegisterNative below
- method->RegisterNative(reinterpret_cast<void*>(&Java_MyClass_fooSIOO));
-
- jvalue a, b, c, d;
- a.i = 0;
- b.l = (jobject)NULL;
- c.l = (jobject)NULL;
- EXPECT_EQ(0, gJava_MyClass_fooSIOO_calls);
- d = RunMethod(method, a, b, c, a);
- ASSERT_EQ((jobject)method->GetClass(), d.l);
- EXPECT_EQ(1, gJava_MyClass_fooSIOO_calls);
- a.i = 0;
- b.l = (jobject)NULL;
- c.l = (jobject)16;
- d = RunMethod(method, a, b, c, a);
- ASSERT_EQ((jobject)method->GetClass(), d.l);
- EXPECT_EQ(2, gJava_MyClass_fooSIOO_calls);
- a.i = 1;
- d = RunMethod(method, a, b, c, a);
- ASSERT_EQ((jobject)NULL, d.l);
- EXPECT_EQ(3, gJava_MyClass_fooSIOO_calls);
- a.i = 2;
- d = RunMethod(method, a, b, c, a);
- ASSERT_EQ((jobject)16, d.l);
- EXPECT_EQ(4, gJava_MyClass_fooSIOO_calls);
- a.i = 0;
- b.l = (jobject)16;
- c.l = (jobject)NULL;
- d = RunMethod(method, a, b, c, a);
- ASSERT_EQ((jobject)method->GetClass(), d.l);
- EXPECT_EQ(5, gJava_MyClass_fooSIOO_calls);
- a.i = 1;
- d = RunMethod(method, a, b, c, a);
- ASSERT_EQ((jobject)16, d.l);
- EXPECT_EQ(6, gJava_MyClass_fooSIOO_calls);
- a.i = 2;
- d = RunMethod(method, a, b, c, a);
- ASSERT_EQ((jobject)NULL, d.l);
- EXPECT_EQ(7, gJava_MyClass_fooSIOO_calls);
-}
-
TEST_F(JniCompilerTest, CompileAndRunStaticSynchronizedIntObjectObjectMethod) {
- scoped_ptr<DexFile> dex(OpenDexFileBase64(kMyClassNativesDex));
- PathClassLoader* class_loader = AllocPathClassLoader(dex.get());
+ SetupForTest(true, "fooSSIOO",
+ "(ILjava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;",
+ reinterpret_cast<void*>(&Java_MyClass_fooSSIOO));
- Class* klass = class_linker_->FindClass("LMyClass;", class_loader);
- ASSERT_TRUE(klass != NULL);
-
- Method* method = klass->FindDirectMethod(
- "fooSSIOO",
- "(ILjava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
- ASSERT_TRUE(method != NULL);
-
- Assembler jni_asm;
- JniCompiler jni_compiler;
- jni_compiler.Compile(&jni_asm, method);
-
- // TODO: should really use JNIEnv to RegisterNative, but missing a
- // complete story on this, so hack the RegisterNative below
- method->RegisterNative(reinterpret_cast<void*>(&Java_MyClass_fooSSIOO));
-
- jvalue a, b, c, d;
- a.i = 0;
- b.l = (jobject)NULL;
- c.l = (jobject)NULL;
EXPECT_EQ(0, gJava_MyClass_fooSSIOO_calls);
- d = RunMethod(method, a, b, c, a);
- ASSERT_EQ((jobject)method->GetClass(), d.l);
+ jobject result = env_->CallStaticObjectMethod(jklass_, jmethod_, 0, NULL, NULL);
+ EXPECT_TRUE(env_->IsSameObject(jklass_, result));
EXPECT_EQ(1, gJava_MyClass_fooSSIOO_calls);
- a.i = 0;
- b.l = (jobject)NULL;
- c.l = (jobject)16;
- d = RunMethod(method, a, b, c, a);
- ASSERT_EQ((jobject)method->GetClass(), d.l);
+
+ result = env_->CallStaticObjectMethod(jklass_, jmethod_, 0, NULL, jobj_);
+ EXPECT_TRUE(env_->IsSameObject(jklass_, result));
EXPECT_EQ(2, gJava_MyClass_fooSSIOO_calls);
- a.i = 1;
- d = RunMethod(method, a, b, c, a);
- ASSERT_EQ((jobject)NULL, d.l);
+ result = env_->CallStaticObjectMethod(jklass_, jmethod_, 1, NULL, jobj_);
+ EXPECT_TRUE(env_->IsSameObject(NULL, result));
EXPECT_EQ(3, gJava_MyClass_fooSSIOO_calls);
- a.i = 2;
- d = RunMethod(method, a, b, c, a);
- ASSERT_EQ((jobject)16, d.l);
+ result = env_->CallStaticObjectMethod(jklass_, jmethod_, 2, NULL, jobj_);
+ EXPECT_TRUE(env_->IsSameObject(jobj_, result));
EXPECT_EQ(4, gJava_MyClass_fooSSIOO_calls);
- a.i = 0;
- b.l = (jobject)16;
- c.l = (jobject)NULL;
- d = RunMethod(method, a, b, c, a);
- ASSERT_EQ((jobject)method->GetClass(), d.l);
+
+ result = env_->CallStaticObjectMethod(jklass_, jmethod_, 0, jobj_, NULL);
+ EXPECT_TRUE(env_->IsSameObject(jklass_, result));
EXPECT_EQ(5, gJava_MyClass_fooSSIOO_calls);
- a.i = 1;
- d = RunMethod(method, a, b, c, a);
- ASSERT_EQ((jobject)16, d.l);
+ result = env_->CallStaticObjectMethod(jklass_, jmethod_, 1, jobj_, NULL);
+ EXPECT_TRUE(env_->IsSameObject(jobj_, result));
EXPECT_EQ(6, gJava_MyClass_fooSSIOO_calls);
- a.i = 2;
- d = RunMethod(method, a, b, c, a);
- ASSERT_EQ((jobject)NULL, d.l);
+ result = env_->CallStaticObjectMethod(jklass_, jmethod_, 2, jobj_, NULL);
+ EXPECT_TRUE(env_->IsSameObject(NULL, result));
EXPECT_EQ(7, gJava_MyClass_fooSSIOO_calls);
}
@@ -510,41 +339,24 @@
gSuspendCounterHandler_calls++;
Thread::Current()->DecrementSuspendCount();
}
+
TEST_F(JniCompilerTest, SuspendCountAcknowledgement) {
- scoped_ptr<DexFile> dex(OpenDexFileBase64(kMyClassNativesDex));
- PathClassLoader* class_loader = AllocPathClassLoader(dex.get());
-
- Class* klass = class_linker_->FindClass("LMyClass;", class_loader);
- ASSERT_TRUE(klass != NULL);
-
- Method* method = klass->FindVirtualMethod("fooI", "(I)I");
- ASSERT_TRUE(method != NULL);
-
- Assembler jni_asm;
- JniCompiler jni_compiler;
- jni_compiler.Compile(&jni_asm, method);
-
- // TODO: should really use JNIEnv to RegisterNative, but missing a
- // complete story on this, so hack the RegisterNative below
- method->RegisterNative(reinterpret_cast<void*>(&Java_MyClass_fooI));
+ SetupForTest(false, "fooI", "(I)I",
+ reinterpret_cast<void*>(&Java_MyClass_fooI));
Thread::Current()->RegisterSuspendCountEntryPoint(&SuspendCountHandler);
- gSuspendCounterHandler_calls = 0;
gJava_MyClass_fooI_calls = 0;
- jvalue a, b, c;
- a.l = (jobject)NULL;
- b.i = 42;
- c = RunMethod(method, a, b, a, a);
- ASSERT_EQ(42, c.i);
+ jint result = env_->CallNonvirtualIntMethod(jobj_, jklass_, jmethod_, 42);
+ EXPECT_EQ(42, result);
EXPECT_EQ(1, gJava_MyClass_fooI_calls);
EXPECT_EQ(0, gSuspendCounterHandler_calls);
Thread::Current()->IncrementSuspendCount();
- c = RunMethod(method, a, b, a, a);
- ASSERT_EQ(42, c.i);
+ result = env_->CallNonvirtualIntMethod(jobj_, jklass_, jmethod_, 42);
+ EXPECT_EQ(42, result);
EXPECT_EQ(2, gJava_MyClass_fooI_calls);
EXPECT_EQ(1, gSuspendCounterHandler_calls);
- c = RunMethod(method, a, b, a, a);
- ASSERT_EQ(42, c.i);
+ result = env_->CallNonvirtualIntMethod(jobj_, jklass_, jmethod_, 42);
+ EXPECT_EQ(42, result);
EXPECT_EQ(3, gJava_MyClass_fooI_calls);
EXPECT_EQ(1, gSuspendCounterHandler_calls);
}
@@ -555,38 +367,21 @@
gExceptionHandler_calls++;
Thread::Current()->ClearException();
}
+
TEST_F(JniCompilerTest, ExceptionHandling) {
- scoped_ptr<DexFile> dex(OpenDexFileBase64(kMyClassNativesDex));
- PathClassLoader* class_loader = AllocPathClassLoader(dex.get());
-
- Class* klass = class_linker_->FindClass("LMyClass;", class_loader);
- ASSERT_TRUE(klass != NULL);
-
- Method* method = klass->FindVirtualMethod("foo", "()V");
- ASSERT_TRUE(method != NULL);
-
- Assembler jni_asm;
- JniCompiler jni_compiler;
- jni_compiler.Compile(&jni_asm, method);
-
- // TODO: should really use JNIEnv to RegisterNative, but missing a
- // complete story on this, so hack the RegisterNative below
- method->RegisterNative(reinterpret_cast<void*>(&Java_MyClass_foo));
+ SetupForTest(false, "foo", "()V", reinterpret_cast<void*>(&Java_MyClass_foo));
Thread::Current()->RegisterExceptionEntryPoint(&ExceptionHandler);
- gExceptionHandler_calls = 0;
gJava_MyClass_foo_calls = 0;
- jvalue a;
- a.l = (jobject)NULL;
- RunMethod(method, a, a, a, a);
+ env_->CallNonvirtualVoidMethod(jobj_, jklass_, jmethod_);
EXPECT_EQ(1, gJava_MyClass_foo_calls);
EXPECT_EQ(0, gExceptionHandler_calls);
// TODO: create a real exception here
- Thread::Current()->SetException(reinterpret_cast<Object*>(8));
- RunMethod(method, a, a, a, a);
+ Thread::Current()->SetException(reinterpret_cast<Object*>(jobj_));
+ env_->CallNonvirtualVoidMethod(jobj_, jklass_, jmethod_);
EXPECT_EQ(2, gJava_MyClass_foo_calls);
EXPECT_EQ(1, gExceptionHandler_calls);
- RunMethod(method, a, a, a, a);
+ env_->CallNonvirtualVoidMethod(jobj_, jklass_, jmethod_);
EXPECT_EQ(3, gJava_MyClass_foo_calls);
EXPECT_EQ(1, gExceptionHandler_calls);
}
diff --git a/src/jni_internal.cc b/src/jni_internal.cc
index fd66d73..9fd0e5f 100644
--- a/src/jni_internal.cc
+++ b/src/jni_internal.cc
@@ -20,6 +20,12 @@
namespace art {
+jobject NewObjectV(JNIEnv* env, jclass clazz, jmethodID methodID, va_list args);
+void CallNonvirtualVoidMethodV(JNIEnv* env, jobject obj, jclass clazz,
+ jmethodID methodID, va_list args);
+void CallNonvirtualVoidMethodA(JNIEnv* env, jobject obj, jclass clazz,
+ jmethodID methodID, jvalue* args);
+
enum JNI_OnLoadState {
kPending = 0, /* initial state, must be zero */
kFailed,
@@ -499,28 +505,36 @@
return arg_array.release();
}
-JValue InvokeWithArgArray(ScopedJniThreadState& ts,
- Object* obj, jmethodID method_id, byte* args) {
+JValue InvokeWithArgArray(ScopedJniThreadState& ts, jobject obj,
+ jmethodID method_id, byte* args) {
// TODO: DecodeReference
Method* method = reinterpret_cast<Method*>(method_id);
+ Object* rcvr = Decode<Object*>(ts, obj);
// Call the invoke stub associated with the method
// Pass everything as arguments
const Method::InvokeStub* stub = method->GetInvokeStub();
CHECK(stub != NULL);
JValue result;
- (*stub)(method, obj, ts.Self(), args, &result);
+ // TODO: we should always have code associated with a method
+ if (method->GetCode()) {
+ (*stub)(method, rcvr, ts.Self(), args, &result);
+ } else {
+ // TODO: pretty print method here
+ LOG(WARNING) << "Not invoking method with no associated code";
+ result.j = 0;
+ }
return result;
}
-JValue InvokeWithJValues(ScopedJniThreadState& ts,
- Object* obj, jmethodID method_id, jvalue* args) {
+JValue InvokeWithJValues(ScopedJniThreadState& ts, jobject obj,
+ jmethodID method_id, jvalue* args) {
Method* method = reinterpret_cast<Method*>(method_id);
scoped_array<byte> arg_array(CreateArgArray(ts, method, args));
return InvokeWithArgArray(ts, obj, method_id, arg_array.get());
}
-JValue InvokeWithVarArgs(ScopedJniThreadState& ts,
- Object* obj, jmethodID method_id, va_list args) {
+JValue InvokeWithVarArgs(ScopedJniThreadState& ts, jobject obj,
+ jmethodID method_id, va_list args) {
Method* method = reinterpret_cast<Method*>(method_id);
scoped_array<byte> arg_array(CreateArgArray(ts, method, args));
return InvokeWithArgArray(ts, obj, method_id, arg_array.get());
@@ -761,8 +775,8 @@
jboolean IsSameObject(JNIEnv* env, jobject obj1, jobject obj2) {
ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return JNI_FALSE;
+ return (Decode<Object*>(ts, obj1) == Decode<Object*>(ts, obj2))
+ ? JNI_TRUE : JNI_FALSE;
}
jint EnsureLocalCapacity(JNIEnv* env, jint) {
@@ -779,22 +793,31 @@
jobject NewObject(JNIEnv* env, jclass clazz, jmethodID methodID, ...) {
ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return NULL;
+ va_list args;
+ va_start(args, methodID);
+ jobject result = NewObjectV(env, clazz, methodID, args);
+ va_end(args);
+ return result;
}
jobject NewObjectV(JNIEnv* env,
jclass clazz, jmethodID methodID, va_list args) {
ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return NULL;
+ Class* klass = Decode<Class*>(ts, clazz);
+ Object* result = klass->NewInstance();
+ jobject local_result = AddLocalReference<jobject>(ts, result);
+ CallNonvirtualVoidMethodV(env, local_result, clazz, methodID, args);
+ return local_result;
}
jobject NewObjectA(JNIEnv* env,
jclass clazz, jmethodID methodID, jvalue* args) {
ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return NULL;
+ Class* klass = Decode<Class*>(ts, clazz);
+ Object* result = klass->NewInstance();
+ jobject local_result = AddLocalReference<jobjectArray>(ts, result);
+ CallNonvirtualVoidMethodA(env, local_result, clazz, methodID, args);
+ return local_result;
}
jclass GetObjectClass(JNIEnv* env, jobject obj) {
@@ -1056,208 +1079,223 @@
jobject CallNonvirtualObjectMethod(JNIEnv* env,
jobject obj, jclass clazz, jmethodID methodID, ...) {
ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return NULL;
+ va_list ap;
+ va_start(ap, methodID);
+ JValue result = InvokeWithVarArgs(ts, obj, methodID, ap);
+ jobject local_result = AddLocalReference<jobject>(ts, result.l);
+ va_end(ap);
+ return local_result;
}
jobject CallNonvirtualObjectMethodV(JNIEnv* env,
jobject obj, jclass clazz, jmethodID methodID, va_list args) {
ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return NULL;
+ JValue result = InvokeWithVarArgs(ts, obj, methodID, args);
+ return AddLocalReference<jobject>(ts, result.l);
}
jobject CallNonvirtualObjectMethodA(JNIEnv* env,
jobject obj, jclass clazz, jmethodID methodID, jvalue* args) {
ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return NULL;
+ JValue result = InvokeWithJValues(ts, obj, methodID, args);
+ return AddLocalReference<jobject>(ts, result.l);
}
jboolean CallNonvirtualBooleanMethod(JNIEnv* env,
jobject obj, jclass clazz, jmethodID methodID, ...) {
ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return JNI_FALSE;
+ va_list ap;
+ va_start(ap, methodID);
+ JValue result = InvokeWithVarArgs(ts, obj, methodID, ap);
+ va_end(ap);
+ return result.z;
}
jboolean CallNonvirtualBooleanMethodV(JNIEnv* env,
jobject obj, jclass clazz, jmethodID methodID, va_list args) {
ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return JNI_FALSE;
+ return InvokeWithVarArgs(ts, obj, methodID, args).z;
}
jboolean CallNonvirtualBooleanMethodA(JNIEnv* env,
jobject obj, jclass clazz, jmethodID methodID, jvalue* args) {
ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return JNI_FALSE;
+ return InvokeWithJValues(ts, obj, methodID, args).z;
}
jbyte CallNonvirtualByteMethod(JNIEnv* env,
jobject obj, jclass clazz, jmethodID methodID, ...) {
ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return 0;
+ va_list ap;
+ va_start(ap, methodID);
+ JValue result = InvokeWithVarArgs(ts, obj, methodID, ap);
+ va_end(ap);
+ return result.b;
}
jbyte CallNonvirtualByteMethodV(JNIEnv* env,
jobject obj, jclass clazz, jmethodID methodID, va_list args) {
ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return 0;
+ return InvokeWithVarArgs(ts, obj, methodID, args).b;
}
jbyte CallNonvirtualByteMethodA(JNIEnv* env,
jobject obj, jclass clazz, jmethodID methodID, jvalue* args) {
ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return 0;
+ return InvokeWithJValues(ts, obj, methodID, args).b;
}
jchar CallNonvirtualCharMethod(JNIEnv* env,
jobject obj, jclass clazz, jmethodID methodID, ...) {
ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return 0;
+ va_list ap;
+ va_start(ap, methodID);
+ JValue result = InvokeWithVarArgs(ts, obj, methodID, ap);
+ va_end(ap);
+ return result.c;
}
jchar CallNonvirtualCharMethodV(JNIEnv* env,
jobject obj, jclass clazz, jmethodID methodID, va_list args) {
ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return 0;
+ return InvokeWithVarArgs(ts, obj, methodID, args).c;
}
jchar CallNonvirtualCharMethodA(JNIEnv* env,
jobject obj, jclass clazz, jmethodID methodID, jvalue* args) {
ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return 0;
+ return InvokeWithJValues(ts, obj, methodID, args).c;
}
jshort CallNonvirtualShortMethod(JNIEnv* env,
jobject obj, jclass clazz, jmethodID methodID, ...) {
ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return 0;
+ va_list ap;
+ va_start(ap, methodID);
+ JValue result = InvokeWithVarArgs(ts, obj, methodID, ap);
+ va_end(ap);
+ return result.s;
}
jshort CallNonvirtualShortMethodV(JNIEnv* env,
jobject obj, jclass clazz, jmethodID methodID, va_list args) {
ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return 0;
+ return InvokeWithVarArgs(ts, obj, methodID, args).s;
}
jshort CallNonvirtualShortMethodA(JNIEnv* env,
jobject obj, jclass clazz, jmethodID methodID, jvalue* args) {
ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return 0;
+ return InvokeWithJValues(ts, obj, methodID, args).s;
}
jint CallNonvirtualIntMethod(JNIEnv* env,
jobject obj, jclass clazz, jmethodID methodID, ...) {
ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return 0;
+ va_list ap;
+ va_start(ap, methodID);
+ JValue result = InvokeWithVarArgs(ts, obj, methodID, ap);
+ va_end(ap);
+ return result.i;
}
jint CallNonvirtualIntMethodV(JNIEnv* env,
jobject obj, jclass clazz, jmethodID methodID, va_list args) {
ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return 0;
+ return InvokeWithVarArgs(ts, obj, methodID, args).i;
}
jint CallNonvirtualIntMethodA(JNIEnv* env,
jobject obj, jclass clazz, jmethodID methodID, jvalue* args) {
ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return 0;
+ return InvokeWithJValues(ts, obj, methodID, args).i;
}
jlong CallNonvirtualLongMethod(JNIEnv* env,
jobject obj, jclass clazz, jmethodID methodID, ...) {
ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return 0;
+ va_list ap;
+ va_start(ap, methodID);
+ JValue result = InvokeWithVarArgs(ts, obj, methodID, ap);
+ va_end(ap);
+ return result.j;
}
jlong CallNonvirtualLongMethodV(JNIEnv* env,
jobject obj, jclass clazz, jmethodID methodID, va_list args) {
ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return 0;
+ return InvokeWithVarArgs(ts, obj, methodID, args).j;
}
jlong CallNonvirtualLongMethodA(JNIEnv* env,
jobject obj, jclass clazz, jmethodID methodID, jvalue* args) {
ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return 0;
+ return InvokeWithJValues(ts, obj, methodID, args).j;
}
jfloat CallNonvirtualFloatMethod(JNIEnv* env,
jobject obj, jclass clazz, jmethodID methodID, ...) {
ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return 0;
+ va_list ap;
+ va_start(ap, methodID);
+ JValue result = InvokeWithVarArgs(ts, obj, methodID, ap);
+ va_end(ap);
+ return result.f;
}
jfloat CallNonvirtualFloatMethodV(JNIEnv* env,
jobject obj, jclass clazz, jmethodID methodID, va_list args) {
ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return 0;
+ return InvokeWithVarArgs(ts, obj, methodID, args).f;
}
jfloat CallNonvirtualFloatMethodA(JNIEnv* env,
jobject obj, jclass clazz, jmethodID methodID, jvalue* args) {
ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return 0;
+ return InvokeWithJValues(ts, obj, methodID, args).f;
}
jdouble CallNonvirtualDoubleMethod(JNIEnv* env,
jobject obj, jclass clazz, jmethodID methodID, ...) {
ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return 0;
+ va_list ap;
+ va_start(ap, methodID);
+ JValue result = InvokeWithVarArgs(ts, obj, methodID, ap);
+ va_end(ap);
+ return result.d;
}
jdouble CallNonvirtualDoubleMethodV(JNIEnv* env,
jobject obj, jclass clazz, jmethodID methodID, va_list args) {
ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return 0;
+ return InvokeWithVarArgs(ts, obj, methodID, args).d;
}
jdouble CallNonvirtualDoubleMethodA(JNIEnv* env,
jobject obj, jclass clazz, jmethodID methodID, jvalue* args) {
ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return 0;
+ return InvokeWithJValues(ts, obj, methodID, args).d;
}
void CallNonvirtualVoidMethod(JNIEnv* env,
jobject obj, jclass clazz, jmethodID methodID, ...) {
ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
+ va_list ap;
+ va_start(ap, methodID);
+ InvokeWithVarArgs(ts, obj, methodID, ap);
+ va_end(ap);
}
void CallNonvirtualVoidMethodV(JNIEnv* env,
jobject obj, jclass clazz, jmethodID methodID, va_list args) {
ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
+ InvokeWithVarArgs(ts, obj, methodID, args);
}
void CallNonvirtualVoidMethodA(JNIEnv* env,
jobject obj, jclass clazz, jmethodID methodID, jvalue* args) {
ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
+ InvokeWithJValues(ts, obj, methodID, args);
}
jfieldID GetFieldID(JNIEnv* env,
@@ -1409,7 +1447,9 @@
va_list ap;
va_start(ap, methodID);
JValue result = InvokeWithVarArgs(ts, NULL, methodID, ap);
- return AddLocalReference<jobject>(ts, result.l);
+ jobject local_result = AddLocalReference<jobject>(ts, result.l);
+ va_end(ap);
+ return local_result;
}
jobject CallStaticObjectMethodV(JNIEnv* env,
@@ -1431,7 +1471,9 @@
ScopedJniThreadState ts(env);
va_list ap;
va_start(ap, methodID);
- return InvokeWithVarArgs(ts, NULL, methodID, ap).z;
+ JValue result = InvokeWithVarArgs(ts, NULL, methodID, ap);
+ va_end(ap);
+ return result.z;
}
jboolean CallStaticBooleanMethodV(JNIEnv* env,
@@ -1450,7 +1492,9 @@
ScopedJniThreadState ts(env);
va_list ap;
va_start(ap, methodID);
- return InvokeWithVarArgs(ts, NULL, methodID, ap).b;
+ JValue result = InvokeWithVarArgs(ts, NULL, methodID, ap);
+ va_end(ap);
+ return result.b;
}
jbyte CallStaticByteMethodV(JNIEnv* env,
@@ -1469,7 +1513,9 @@
ScopedJniThreadState ts(env);
va_list ap;
va_start(ap, methodID);
- return InvokeWithVarArgs(ts, NULL, methodID, ap).c;
+ JValue result = InvokeWithVarArgs(ts, NULL, methodID, ap);
+ va_end(ap);
+ return result.c;
}
jchar CallStaticCharMethodV(JNIEnv* env,
@@ -1488,7 +1534,9 @@
ScopedJniThreadState ts(env);
va_list ap;
va_start(ap, methodID);
- return InvokeWithVarArgs(ts, NULL, methodID, ap).s;
+ JValue result = InvokeWithVarArgs(ts, NULL, methodID, ap);
+ va_end(ap);
+ return result.s;
}
jshort CallStaticShortMethodV(JNIEnv* env,
@@ -1507,7 +1555,9 @@
ScopedJniThreadState ts(env);
va_list ap;
va_start(ap, methodID);
- return InvokeWithVarArgs(ts, NULL, methodID, ap).i;
+ JValue result = InvokeWithVarArgs(ts, NULL, methodID, ap);
+ va_end(ap);
+ return result.i;
}
jint CallStaticIntMethodV(JNIEnv* env,
@@ -1526,7 +1576,9 @@
ScopedJniThreadState ts(env);
va_list ap;
va_start(ap, methodID);
- return InvokeWithVarArgs(ts, NULL, methodID, ap).j;
+ JValue result = InvokeWithVarArgs(ts, NULL, methodID, ap);
+ va_end(ap);
+ return result.j;
}
jlong CallStaticLongMethodV(JNIEnv* env,
@@ -1545,7 +1597,9 @@
ScopedJniThreadState ts(env);
va_list ap;
va_start(ap, methodID);
- return InvokeWithVarArgs(ts, NULL, methodID, ap).f;
+ JValue result = InvokeWithVarArgs(ts, NULL, methodID, ap);
+ va_end(ap);
+ return result.f;
}
jfloat CallStaticFloatMethodV(JNIEnv* env,
@@ -1564,7 +1618,9 @@
ScopedJniThreadState ts(env);
va_list ap;
va_start(ap, methodID);
- return InvokeWithVarArgs(ts, NULL, methodID, ap).d;
+ JValue result = InvokeWithVarArgs(ts, NULL, methodID, ap);
+ va_end(ap);
+ return result.d;
}
jdouble CallStaticDoubleMethodV(JNIEnv* env,
@@ -1584,6 +1640,7 @@
va_list ap;
va_start(ap, methodID);
InvokeWithVarArgs(ts, NULL, methodID, ap);
+ va_end(ap);
}
void CallStaticVoidMethodV(JNIEnv* env,
diff --git a/src/jni_internal_arm.cc b/src/jni_internal_arm.cc
index b2777d6..e126b6e 100644
--- a/src/jni_internal_arm.cc
+++ b/src/jni_internal_arm.cc
@@ -19,8 +19,8 @@
// R0 = method pointer
// R1 = receiver pointer or NULL for static methods
// R2 = (managed) thread pointer
-// R3 = argument array or NULL for void arugment methods
-// [SP] = JValue result or NULL for void returns
+// R3 = argument array or NULL for no argument methods
+// [SP] = JValue* result or NULL for void returns
//
// As the JNI call has already transitioned the thread into the
// "running" state the remaining responsibilities of this routine are
@@ -29,77 +29,76 @@
// the stack, if needed. On return, the thread register must be
// shuffled and the return value must be store into the result JValue.
void CreateInvokeStub(Assembler* assembler, Method* method) {
- size_t num_arg_words = method->NumArgArrayBytes() / kWordSize;
- // TODO: the incoming argument array should have implicit arguments.
- size_t max_register_words = method->IsStatic() ? 3 : 2;
- size_t num_register_words = std::min(num_arg_words, max_register_words);
- size_t num_stack_words = num_arg_words - num_register_words;
+ // Size of frame - spill of R9/LR + Method* + possible receiver + arg array
+ size_t unpadded_frame_size = (3 * kPointerSize) +
+ (method->IsStatic() ? 0 : kPointerSize) +
+ method->NumArgArrayBytes();
+ size_t frame_size = RoundUp(unpadded_frame_size, kStackAlignment);
- // For now we allocate stack space for stacked outgoing arguments.
- size_t stack_parameters_size = num_stack_words*kWordSize;
- if (num_arg_words != RoundUp(num_arg_words,8)) {
- // Ensure 8-byte alignment.
- stack_parameters_size += kWordSize;
- }
-
+ // Spill R9 and LR
RegList save = (1 << R9);
__ PushList(save | (1 << LR));
- // Allocate a frame large enough for the stacked arguments.
- __ AddConstant(SP, -stack_parameters_size);
-
// Move the managed thread pointer into R9.
__ mov(R9, ShifterOperand(R2));
- // Move all stacked arguments into place.
- size_t first_stack_word = num_register_words;
- if (num_arg_words > max_register_words) {
- for (size_t i = first_stack_word, j = 0; i < num_arg_words; ++i, ++j) {
- int r3_offset = i * kWordSize;
- int sp_offset = j * kWordSize;
- __ LoadFromOffset(kLoadWord, IP, R3, r3_offset);
- __ StoreToOffset(kStoreWord, IP, SP, sp_offset);
- }
+ // Move frame down for arguments less 2 pushed values above
+ __ AddConstant(SP, -frame_size + (2 * kPointerSize));
+
+ // Can either get 3 or 2 arguments into registers
+ size_t reg_bytes = (method->IsStatic() ? 3 : 2) * kPointerSize;
+ // Bytes passed by stack
+ size_t stack_bytes;
+ if( method->NumArgArrayBytes() > reg_bytes){
+ stack_bytes = method->NumArgArrayBytes() - reg_bytes;
+ } else {
+ stack_bytes = 0;
+ reg_bytes = method->NumArgArrayBytes();
+ }
+
+ // Copy values by stack
+ for(size_t off = 0; off < stack_bytes; off += kPointerSize) {
+ // we're displaced off of r3 by bytes that'll go in registers
+ int r3_offset = reg_bytes + off;
+ __ LoadFromOffset(kLoadWord, IP, R3, r3_offset);
+
+ // we're displaced off of the arguments by the spill space for the incoming
+ // arguments and the Method*
+ int sp_offset = reg_bytes + kPointerSize + off;
+ __ StoreToOffset(kStoreWord, IP, SP, sp_offset);
}
// Move all the register arguments into place.
if (method->IsStatic()) {
- if (num_register_words > 0) {
+ if (reg_bytes > 0) {
__ LoadFromOffset(kLoadWord, R1, R3, 0);
- }
- if (num_register_words > 1) {
- __ LoadFromOffset(kLoadWord, R2, R3, 4);
- }
- if (num_register_words > 2) {
- __ LoadFromOffset(kLoadWord, R3, R3, 8);
+ if (reg_bytes > 4) {
+ __ LoadFromOffset(kLoadWord, R2, R3, 4);
+ if (reg_bytes > 8) {
+ __ LoadFromOffset(kLoadWord, R3, R3, 8);
+ }
+ }
}
} else {
- if (num_register_words > 0) {
+ if (reg_bytes > 0) {
__ LoadFromOffset(kLoadWord, R2, R3, 0);
- }
- if (num_register_words > 1) {
- __ LoadFromOffset(kLoadWord, R3, R3, 4);
+ if (reg_bytes > 4) {
+ __ LoadFromOffset(kLoadWord, R3, R3, 4);
+ }
}
}
- // Allocate the spill area for outgoing arguments.
- __ AddConstant(SP, -((num_register_words+1)*kWordSize));
-
// Load the code pointer we are about to call.
__ LoadFromOffset(kLoadWord, IP, R0, method->GetCodeOffset());
// Do the call.
__ blx(IP);
- // Deallocate the spill area for outgoing arguments.
- __ AddConstant(SP, ((num_register_words+1)*kWordSize));
-
// If the method returns a value, store it to the result pointer.
char ch = method->GetShorty()[0];
if (ch != 'V') {
- // Load the result JValue pointer. It is the first stacked
- // argument so it is stored above the stacked R9 and LR values.
- __ LoadFromOffset(kLoadWord, IP, SP, stack_parameters_size + 2*kWordSize);
+ // Load the result JValue pointer of the stub caller's out args.
+ __ LoadFromOffset(kLoadWord, IP, SP, frame_size);
if (ch == 'D' || ch == 'J') {
__ StoreToOffset(kStoreWordPair, R0, IP, 0);
} else {
@@ -107,7 +106,10 @@
}
}
- __ AddConstant(SP, stack_parameters_size);
+ // Remove the frame less the spilled R9 and LR
+ __ AddConstant(SP, frame_size - (2 * kPointerSize));
+
+ // Pop R9 and the LR into PC
__ PopList(save | (1 << PC));
}
diff --git a/src/jni_internal_test.cc b/src/jni_internal_test.cc
index 9957565..f51b6c9 100644
--- a/src/jni_internal_test.cc
+++ b/src/jni_internal_test.cc
@@ -76,11 +76,9 @@
env_->ExceptionClear();
// Check that java.lang.Object.equals() does exist
-#if defined(__arm__)
method = env_->GetMethodID(jlobject, "equals", "(Ljava/lang/Object;)Z");
EXPECT_NE(static_cast<jmethodID>(NULL), method);
EXPECT_FALSE(env_->ExceptionCheck());
-#endif
// Check that GetMethodID for java.lang.String.valueOf(int) fails as the
// method is static
@@ -121,13 +119,11 @@
env_->ExceptionClear();
// Check that java.lang.String.valueOf(int) does exist
-#if defined(__arm__)
jclass jlstring = env_->FindClass("java/lang/String");
method = env_->GetStaticMethodID(jlstring, "valueOf",
"(I)Ljava/lang/String;");
EXPECT_NE(static_cast<jmethodID>(NULL), method);
EXPECT_FALSE(env_->ExceptionCheck());
-#endif
}
TEST_F(JniInternalTest, RegisterNatives) {
diff --git a/src/jni_internal_x86.cc b/src/jni_internal_x86.cc
index 82fbb57..05542b7 100644
--- a/src/jni_internal_x86.cc
+++ b/src/jni_internal_x86.cc
@@ -7,8 +7,76 @@
namespace art {
+
+#define __ assembler->
+
+// Creates a function which invokes a managed method with an array of
+// arguments.
+//
+// Immediately after the call, the environment looks like this:
+//
+// [SP+0 ] = Return address
+// [SP+4 ]= method pointer
+// [SP+8 ] = receiver pointer or NULL for static methods
+// [SP+12] = (managed) thread pointer
+// [SP+16] = argument array or NULL for no argument methods
+// [SP+20] = JValue* result or NULL for void returns
+//
+// As the JNI call has already transitioned the thread into the
+// "running" state the remaining responsibilities of this routine are
+// to save the native registers and set up the managed registers. On
+// return, the return value must be store into the result JValue.
void CreateInvokeStub(Assembler* assembler, Method* method) {
- UNIMPLEMENTED(FATAL);
+ // Size of frame - spill of EDI + Method* + possible receiver + arg array
+ size_t frame_size = (2 * kPointerSize) +
+ (method->IsStatic() ? 0 : kPointerSize) +
+ method->NumArgArrayBytes();
+ size_t pad_size = RoundUp(frame_size, kStackAlignment) - frame_size;
+
+ __ pushl(EDI); // preserve EDI
+ __ movl(EDI, Address(ESP, 8)); // EDI = method
+ __ movl(EAX, Address(ESP, 12)); // EAX = receiver
+ __ movl(EDX, Address(ESP, 20)); // EDX = arg array
+
+ // Push padding
+ if (pad_size != 0) {
+ __ addl(ESP, Immediate(-pad_size));
+ }
+
+ // Push/copy arguments
+ for (size_t off = method->NumArgArrayBytes(); off > 0; off -= kPointerSize) {
+ __ pushl(Address(EDX, off - kPointerSize));
+ }
+ if (!method->IsStatic()) {
+ __ pushl(EAX);
+ }
+ __ pushl(EDI); // Method* at bottom of fake managed frame
+ __ call(Address(EDI, method->GetCodeOffset())); // Call code off of method
+
+ // pop arguments and padding up to saved EDI
+ __ addl(ESP, Immediate(frame_size + pad_size - kPointerSize));
+ char ch = method->GetShorty()[0];
+ if (ch != 'V') {
+ // Load the result JValue pointer.
+ __ movl(EDI, Address(ESP, 24));
+ switch(ch) {
+ case 'D':
+ __ fstpl(Address(EDI, 0));
+ break;
+ case 'F':
+ __ fstps(Address(EDI, 0));
+ break;
+ case 'J':
+ __ movl(Address(EDI, 0), EAX);
+ __ movl(Address(EDI, 4), EDX);
+ break;
+ default:
+ __ movl(Address(EDI, 0), EAX);
+ break;
+ }
+ }
+ __ popl(EDI); // restore EDI
+ __ ret();
}
} // namespace art
diff --git a/src/object.h b/src/object.h
index 2384fde..c78103b 100644
--- a/src/object.h
+++ b/src/object.h
@@ -375,8 +375,8 @@
return declaring_class_;
}
- static MemberOffset ClassOffset() {
- return MemberOffset(OFFSETOF_MEMBER(Method, klass_));
+ static MemberOffset DeclaringClassOffset() {
+ return MemberOffset(OFFSETOF_MEMBER(Method, declaring_class_));
}
// Returns true if the method is declared public.