blob: 854df887d0e219080fa6c8750eaa75303f229afc [file] [log] [blame]
Ian Rogersb033c752011-07-20 12:22:35 -07001// Copyright 2011 Google Inc. All Rights Reserved.
Ian Rogersb033c752011-07-20 12:22:35 -07002
3#include <sys/mman.h>
Brian Carlstrom578bbdc2011-07-21 14:07:47 -07004
5#include "assembler.h"
6#include "class_linker.h"
7#include "common_test.h"
8#include "dex_file.h"
9#include "jni_compiler.h"
Brian Carlstromdb4d5402011-08-09 12:18:28 -070010#include "mem_map.h"
Brian Carlstrom578bbdc2011-07-21 14:07:47 -070011#include "runtime.h"
Brian Carlstromdb4d5402011-08-09 12:18:28 -070012#include "scoped_ptr.h"
Brian Carlstrom578bbdc2011-07-21 14:07:47 -070013#include "thread.h"
Ian Rogersb033c752011-07-20 12:22:35 -070014#include "gtest/gtest.h"
15
16namespace art {
17
Brian Carlstromf734cf52011-08-17 16:28:14 -070018class JniCompilerTest : public CommonTest {
Ian Rogersb033c752011-07-20 12:22:35 -070019 protected:
20 virtual void SetUp() {
Brian Carlstromf734cf52011-08-17 16:28:14 -070021 CommonTest::SetUp();
Ian Rogersb033c752011-07-20 12:22:35 -070022 // Create thunk code that performs the native to managed transition
Brian Carlstrom4a289ed2011-08-16 17:17:49 -070023 thunk_code_.reset(MemMap::Map(kPageSize, PROT_READ | PROT_WRITE | PROT_EXEC));
Brian Carlstromdb4d5402011-08-09 12:18:28 -070024 CHECK(thunk_code_ != NULL);
Ian Rogersb033c752011-07-20 12:22:35 -070025 Assembler thk_asm;
26 // TODO: shouldn't have machine specific code in a general purpose file
27#if defined(__i386__)
28 thk_asm.pushl(EDI); // preserve EDI
29 thk_asm.movl(EAX, Address(ESP, 8)); // EAX = method->GetCode()
30 thk_asm.movl(EDI, Address(ESP, 12)); // EDI = method
31 thk_asm.pushl(Immediate(0)); // push pad
32 thk_asm.pushl(Immediate(0)); // push pad
Carl Shapiroe2d373e2011-07-25 15:20:06 -070033 thk_asm.pushl(Address(ESP, 44)); // push pad or jlong high
34 thk_asm.pushl(Address(ESP, 44)); // push jint or jlong low
35 thk_asm.pushl(Address(ESP, 44)); // push jint or jlong high
36 thk_asm.pushl(Address(ESP, 44)); // push jint or jlong low
37 thk_asm.pushl(Address(ESP, 44)); // push jobject
Ian Rogersb033c752011-07-20 12:22:35 -070038 thk_asm.call(EAX); // Continue in method->GetCode()
39 thk_asm.addl(ESP, Immediate(28)); // pop arguments
40 thk_asm.popl(EDI); // restore EDI
41 thk_asm.ret();
Carl Shapiroe2d373e2011-07-25 15:20:06 -070042#elif defined(__arm__)
43 thk_asm.AddConstant(SP, -32); // Build frame
Brian Carlstrom8ecd08c2011-07-27 17:50:51 -070044 thk_asm.StoreToOffset(kStoreWord, LR, SP, 28); // Spill link register
45 thk_asm.StoreToOffset(kStoreWord, R9, SP, 24); // Spill R9
46 thk_asm.mov(R12, ShifterOperand(R0)); // R12 = method->GetCode()
47 thk_asm.mov(R0, ShifterOperand(R1)); // R0 = method
48 thk_asm.mov(R9, ShifterOperand(R2)); // R9 = Thread::Current()
49 thk_asm.mov(R1, ShifterOperand(R3)); // R1 = arg1 (jint/jlong low)
50 thk_asm.LoadFromOffset(kLoadWord, R3, SP, 44); // R3 = arg5 (pad/jlong high)
Carl Shapiroe2d373e2011-07-25 15:20:06 -070051 thk_asm.StoreToOffset(kStoreWord, R3, SP, 4);
Brian Carlstrom8ecd08c2011-07-27 17:50:51 -070052 thk_asm.LoadFromOffset(kLoadWord, R3, SP, 40); // R3 = arg4 (jint/jlong low)
Carl Shapiroe2d373e2011-07-25 15:20:06 -070053 thk_asm.StoreToOffset(kStoreWord, R3, SP, 0);
Brian Carlstrom8ecd08c2011-07-27 17:50:51 -070054 thk_asm.LoadFromOffset(kLoadWord, R3, SP, 36); // R3 = arg3 (jint/jlong high)
55 thk_asm.LoadFromOffset(kLoadWord, R2, SP, 32); // R2 = arg2 (jint/jlong high)
Carl Shapiroe2d373e2011-07-25 15:20:06 -070056 thk_asm.blx(R12); // Branch and link R12
Brian Carlstrom8ecd08c2011-07-27 17:50:51 -070057 thk_asm.LoadFromOffset(kLoadWord, LR, SP, 28); // Fill link register
58 thk_asm.LoadFromOffset(kLoadWord, R9, SP, 24); // Fill R9
Carl Shapiroe2d373e2011-07-25 15:20:06 -070059 thk_asm.AddConstant(SP, 32); // Remove frame
60 thk_asm.mov(PC, ShifterOperand(LR)); // Return
Ian Rogersb033c752011-07-20 12:22:35 -070061#else
Carl Shapiroe2d373e2011-07-25 15:20:06 -070062#error Unimplemented
Ian Rogersb033c752011-07-20 12:22:35 -070063#endif
64 size_t cs = thk_asm.CodeSize();
Brian Carlstromdb4d5402011-08-09 12:18:28 -070065 MemoryRegion code(thunk_code_->GetAddress(), cs);
Ian Rogersb033c752011-07-20 12:22:35 -070066 thk_asm.FinalizeInstructions(code);
67 thunk_entry1_ = reinterpret_cast<jint (*)(const void*, art::Method*,
Carl Shapiroe2d373e2011-07-25 15:20:06 -070068 Thread*, jobject, jint, jint,
69 jint)
Ian Rogersb033c752011-07-20 12:22:35 -070070 >(code.pointer());
71 thunk_entry2_ = reinterpret_cast<jdouble (*)(const void*, art::Method*,
Carl Shapiroe2d373e2011-07-25 15:20:06 -070072 Thread*, jobject, jdouble,
73 jdouble)
Ian Rogersb033c752011-07-20 12:22:35 -070074 >(code.pointer());
75 }
76
77 virtual void TearDown() {
78 // Release thunk code
79 CHECK(runtime_->DetachCurrentThread());
Ian Rogersb033c752011-07-20 12:22:35 -070080 }
81
82 // Run generated code associated with method passing and returning int size
83 // arguments
84 jvalue RunMethod(Method* method, jvalue a, jvalue b, jvalue c, jvalue d) {
85 jvalue result;
86 // sanity checks
87 EXPECT_NE(static_cast<void*>(NULL), method->GetCode());
88 EXPECT_EQ(0u, Thread::Current()->NumShbHandles());
89 EXPECT_EQ(Thread::kRunnable, Thread::Current()->GetState());
90 // perform call
Carl Shapiroe2d373e2011-07-25 15:20:06 -070091 result.i = (*thunk_entry1_)(method->GetCode(), method, Thread::Current(),
92 a.l, b.i, c.i, d.i);
Ian Rogersb033c752011-07-20 12:22:35 -070093 // sanity check post-call
94 EXPECT_EQ(0u, Thread::Current()->NumShbHandles());
95 EXPECT_EQ(Thread::kRunnable, Thread::Current()->GetState());
96 return result;
97 }
98
99 // Run generated code associated with method passing and returning double size
100 // arguments
101 jvalue RunMethodD(Method* method, jvalue a, jvalue b, jvalue c) {
102 jvalue result;
103 // sanity checks
104 EXPECT_NE(static_cast<void*>(NULL), method->GetCode());
105 EXPECT_EQ(0u, Thread::Current()->NumShbHandles());
106 EXPECT_EQ(Thread::kRunnable, Thread::Current()->GetState());
107 // perform call
Carl Shapiroe2d373e2011-07-25 15:20:06 -0700108 result.d = (*thunk_entry2_)(method->GetCode(), method, Thread::Current(),
109 a.l, b.d, c.d);
Ian Rogersb033c752011-07-20 12:22:35 -0700110 // sanity check post-call
111 EXPECT_EQ(0u, Thread::Current()->NumShbHandles());
112 EXPECT_EQ(Thread::kRunnable, Thread::Current()->GetState());
113 return result;
114 }
115
Brian Carlstromdb4d5402011-08-09 12:18:28 -0700116 scoped_ptr<MemMap> thunk_code_;
Carl Shapiroe2d373e2011-07-25 15:20:06 -0700117 jint (*thunk_entry1_)(const void*, Method*, Thread*, jobject, jint, jint,
118 jint);
119 jdouble (*thunk_entry2_)(const void*, Method*, Thread*, jobject, jdouble,
120 jdouble);
Ian Rogersb033c752011-07-20 12:22:35 -0700121};
122
123int gJava_MyClass_foo_calls = 0;
124void Java_MyClass_foo(JNIEnv*, jobject) {
125 EXPECT_EQ(1u, Thread::Current()->NumShbHandles());
126 EXPECT_EQ(Thread::kNative, Thread::Current()->GetState());
127 gJava_MyClass_foo_calls++;
128}
129
130int gJava_MyClass_fooI_calls = 0;
131jint Java_MyClass_fooI(JNIEnv*, jobject, jint x) {
132 EXPECT_EQ(1u, Thread::Current()->NumShbHandles());
133 EXPECT_EQ(Thread::kNative, Thread::Current()->GetState());
134 gJava_MyClass_fooI_calls++;
135 return x;
136}
137
138int gJava_MyClass_fooII_calls = 0;
139jint Java_MyClass_fooII(JNIEnv*, jobject, jint x, jint y) {
140 EXPECT_EQ(1u, Thread::Current()->NumShbHandles());
141 EXPECT_EQ(Thread::kNative, Thread::Current()->GetState());
142 gJava_MyClass_fooII_calls++;
143 return x - y; // non-commutative operator
144}
145
146int gJava_MyClass_fooDD_calls = 0;
147jdouble Java_MyClass_fooDD(JNIEnv*, jobject, jdouble x, jdouble y) {
148 EXPECT_EQ(1u, Thread::Current()->NumShbHandles());
149 EXPECT_EQ(Thread::kNative, Thread::Current()->GetState());
150 gJava_MyClass_fooDD_calls++;
151 return x - y; // non-commutative operator
152}
153
154int gJava_MyClass_fooIOO_calls = 0;
155jobject Java_MyClass_fooIOO(JNIEnv*, jobject thisObject, jint x, jobject y,
156 jobject z) {
157 EXPECT_EQ(3u, Thread::Current()->NumShbHandles());
158 EXPECT_EQ(Thread::kNative, Thread::Current()->GetState());
159 gJava_MyClass_fooIOO_calls++;
160 switch (x) {
161 case 1:
162 return y;
163 case 2:
164 return z;
165 default:
166 return thisObject;
167 }
168}
169
170int gJava_MyClass_fooSIOO_calls = 0;
Elliott Hughes330304d2011-08-12 14:28:05 -0700171jobject Java_MyClass_fooSIOO(JNIEnv* env, jclass klass, jint x, jobject y,
Ian Rogersb033c752011-07-20 12:22:35 -0700172 jobject z) {
Elliott Hughes330304d2011-08-12 14:28:05 -0700173 EXPECT_EQ(Thread::Current()->GetJniEnv(), env);
Ian Rogersb033c752011-07-20 12:22:35 -0700174 EXPECT_EQ(3u, Thread::Current()->NumShbHandles());
175 EXPECT_EQ(Thread::kNative, Thread::Current()->GetState());
176 gJava_MyClass_fooSIOO_calls++;
177 switch (x) {
178 case 1:
179 return y;
180 case 2:
181 return z;
182 default:
183 return klass;
184 }
185}
186
Ian Rogersdf20fe02011-07-20 20:34:16 -0700187int gJava_MyClass_fooSSIOO_calls = 0;
188jobject Java_MyClass_fooSSIOO(JNIEnv*, jclass klass, jint x, jobject y,
189 jobject z) {
190 EXPECT_EQ(3u, Thread::Current()->NumShbHandles());
191 EXPECT_EQ(Thread::kNative, Thread::Current()->GetState());
192 gJava_MyClass_fooSSIOO_calls++;
193 switch (x) {
194 case 1:
195 return y;
196 case 2:
197 return z;
198 default:
199 return klass;
200 }
201}
202
Ian Rogersb033c752011-07-20 12:22:35 -0700203TEST_F(JniCompilerTest, CompileAndRunNoArgMethod) {
Brian Carlstromf615a612011-07-23 12:50:34 -0700204 scoped_ptr<DexFile> dex(OpenDexFileBase64(kMyClassNativesDex));
Brian Carlstrom74eb46a2011-08-02 20:10:14 -0700205 PathClassLoader* class_loader = AllocPathClassLoader(dex.get());
Carl Shapiro419ec7b2011-08-03 14:48:33 -0700206
Brian Carlstrom74eb46a2011-08-02 20:10:14 -0700207 Class* klass = class_linker_->FindClass("LMyClass;", class_loader);
Carl Shapiro419ec7b2011-08-03 14:48:33 -0700208 ASSERT_TRUE(klass != NULL);
209
210 Method* method = klass->FindVirtualMethod("foo", "()V");
211 ASSERT_TRUE(method != NULL);
Ian Rogersb033c752011-07-20 12:22:35 -0700212
213 Assembler jni_asm;
214 JniCompiler jni_compiler;
215 jni_compiler.Compile(&jni_asm, method);
216
217 // TODO: should really use JNIEnv to RegisterNative, but missing a
218 // complete story on this, so hack the RegisterNative below
219 // JNIEnv* env = Thread::Current()->GetJniEnv();
220 // JNINativeMethod methods[] = {{"foo", "()V", (void*)&Java_MyClass_foo}};
221 method->RegisterNative(reinterpret_cast<void*>(&Java_MyClass_foo));
222
223 jvalue a;
224 a.l = (jobject)NULL;
Ian Rogers45a76cb2011-07-21 22:00:15 -0700225 gJava_MyClass_foo_calls = 0;
Ian Rogersb033c752011-07-20 12:22:35 -0700226 RunMethod(method, a, a, a, a);
227 EXPECT_EQ(1, gJava_MyClass_foo_calls);
228 RunMethod(method, a, a, a, a);
229 EXPECT_EQ(2, gJava_MyClass_foo_calls);
230}
231
232TEST_F(JniCompilerTest, CompileAndRunIntMethod) {
Brian Carlstromf615a612011-07-23 12:50:34 -0700233 scoped_ptr<DexFile> dex(OpenDexFileBase64(kMyClassNativesDex));
Brian Carlstrom74eb46a2011-08-02 20:10:14 -0700234 PathClassLoader* class_loader = AllocPathClassLoader(dex.get());
Carl Shapiro419ec7b2011-08-03 14:48:33 -0700235
Brian Carlstrom74eb46a2011-08-02 20:10:14 -0700236 Class* klass = class_linker_->FindClass("LMyClass;", class_loader);
Carl Shapiro419ec7b2011-08-03 14:48:33 -0700237 ASSERT_TRUE(klass != NULL);
238
239 Method* method = klass->FindVirtualMethod("fooI", "(I)I");
240 ASSERT_TRUE(method != NULL);
Ian Rogersb033c752011-07-20 12:22:35 -0700241
242 Assembler jni_asm;
243 JniCompiler jni_compiler;
244 jni_compiler.Compile(&jni_asm, method);
245
246 // TODO: should really use JNIEnv to RegisterNative, but missing a
247 // complete story on this, so hack the RegisterNative below
248 method->RegisterNative(reinterpret_cast<void*>(&Java_MyClass_fooI));
249
250 jvalue a, b, c;
251 a.l = (jobject)NULL;
252 b.i = 42;
253 EXPECT_EQ(0, gJava_MyClass_fooI_calls);
254 c = RunMethod(method, a, b, a, a);
255 ASSERT_EQ(42, c.i);
256 EXPECT_EQ(1, gJava_MyClass_fooI_calls);
257 b.i = 0xCAFED00D;
258 c = RunMethod(method, a, b, a, a);
259 ASSERT_EQ((jint)0xCAFED00D, c.i);
260 EXPECT_EQ(2, gJava_MyClass_fooI_calls);
261}
262
263TEST_F(JniCompilerTest, CompileAndRunIntIntMethod) {
Brian Carlstromf615a612011-07-23 12:50:34 -0700264 scoped_ptr<DexFile> dex(OpenDexFileBase64(kMyClassNativesDex));
Brian Carlstrom74eb46a2011-08-02 20:10:14 -0700265 PathClassLoader* class_loader = AllocPathClassLoader(dex.get());
Carl Shapiro419ec7b2011-08-03 14:48:33 -0700266
Brian Carlstrom74eb46a2011-08-02 20:10:14 -0700267 Class* klass = class_linker_->FindClass("LMyClass;", class_loader);
Carl Shapiro419ec7b2011-08-03 14:48:33 -0700268 ASSERT_TRUE(klass != NULL);
269
270 Method* method = klass->FindVirtualMethod("fooII", "(II)I");
271 ASSERT_TRUE(method != NULL);
Ian Rogersb033c752011-07-20 12:22:35 -0700272
273 Assembler jni_asm;
274 JniCompiler jni_compiler;
275 jni_compiler.Compile(&jni_asm, method);
276
277 // TODO: should really use JNIEnv to RegisterNative, but missing a
278 // complete story on this, so hack the RegisterNative below
279 method->RegisterNative(reinterpret_cast<void*>(&Java_MyClass_fooII));
280
281 jvalue a, b, c, d;
282 a.l = (jobject)NULL;
283 b.i = 99;
284 c.i = 10;
285 EXPECT_EQ(0, gJava_MyClass_fooII_calls);
286 d = RunMethod(method, a, b, c, a);
287 ASSERT_EQ(99 - 10, d.i);
288 EXPECT_EQ(1, gJava_MyClass_fooII_calls);
289 b.i = 0xCAFEBABE;
290 c.i = 0xCAFED00D;
291 d = RunMethod(method, a, b, c, a);
292 ASSERT_EQ((jint)(0xCAFEBABE - 0xCAFED00D), d.i);
293 EXPECT_EQ(2, gJava_MyClass_fooII_calls);
294}
295
296
297TEST_F(JniCompilerTest, CompileAndRunDoubleDoubleMethod) {
Brian Carlstromf615a612011-07-23 12:50:34 -0700298 scoped_ptr<DexFile> dex(OpenDexFileBase64(kMyClassNativesDex));
Brian Carlstrom74eb46a2011-08-02 20:10:14 -0700299 PathClassLoader* class_loader = AllocPathClassLoader(dex.get());
Carl Shapiro419ec7b2011-08-03 14:48:33 -0700300
Brian Carlstrom74eb46a2011-08-02 20:10:14 -0700301 Class* klass = class_linker_->FindClass("LMyClass;", class_loader);
Carl Shapiro419ec7b2011-08-03 14:48:33 -0700302 ASSERT_TRUE(klass != NULL);
303
304 Method* method = klass->FindVirtualMethod("fooDD", "(DD)D");
305 ASSERT_TRUE(method != NULL);
Ian Rogersb033c752011-07-20 12:22:35 -0700306
307 Assembler jni_asm;
308 JniCompiler jni_compiler;
309 jni_compiler.Compile(&jni_asm, method);
310
311 // TODO: should really use JNIEnv to RegisterNative, but missing a
312 // complete story on this, so hack the RegisterNative below
313 method->RegisterNative(reinterpret_cast<void*>(&Java_MyClass_fooDD));
314
315 jvalue a, b, c, d;
316 a.l = (jobject)NULL;
317 b.d = 99;
318 c.d = 10;
319 EXPECT_EQ(0, gJava_MyClass_fooDD_calls);
320 d = RunMethodD(method, a, b, c);
321 ASSERT_EQ(b.d - c.d, d.d);
322 EXPECT_EQ(1, gJava_MyClass_fooDD_calls);
323 b.d = 3.14159265358979323846;
324 c.d = 0.69314718055994530942;
325 d = RunMethodD(method, a, b, c);
326 ASSERT_EQ(b.d - c.d, d.d);
327 EXPECT_EQ(2, gJava_MyClass_fooDD_calls);
328}
329
330TEST_F(JniCompilerTest, CompileAndRunIntObjectObjectMethod) {
Brian Carlstromf615a612011-07-23 12:50:34 -0700331 scoped_ptr<DexFile> dex(OpenDexFileBase64(kMyClassNativesDex));
Brian Carlstrom74eb46a2011-08-02 20:10:14 -0700332 PathClassLoader* class_loader = AllocPathClassLoader(dex.get());
Carl Shapiro419ec7b2011-08-03 14:48:33 -0700333
Brian Carlstrom74eb46a2011-08-02 20:10:14 -0700334 Class* klass = class_linker_->FindClass("LMyClass;", class_loader);
Carl Shapiro419ec7b2011-08-03 14:48:33 -0700335 ASSERT_TRUE(klass != NULL);
336
337 Method* method = klass->FindVirtualMethod(
338 "fooIOO",
339 "(ILjava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
340 ASSERT_TRUE(method != NULL);
Ian Rogersb033c752011-07-20 12:22:35 -0700341
342 Assembler jni_asm;
343 JniCompiler jni_compiler;
344 jni_compiler.Compile(&jni_asm, method);
345
346 // TODO: should really use JNIEnv to RegisterNative, but missing a
347 // complete story on this, so hack the RegisterNative below
348 method->RegisterNative(reinterpret_cast<void*>(&Java_MyClass_fooIOO));
349
350 jvalue a, b, c, d, e;
351 a.l = (jobject)NULL;
352 b.i = 0;
353 c.l = (jobject)NULL;
354 d.l = (jobject)NULL;
355 EXPECT_EQ(0, gJava_MyClass_fooIOO_calls);
356 e = RunMethod(method, a, b, c, d);
357 ASSERT_EQ((jobject)NULL, e.l);
358 EXPECT_EQ(1, gJava_MyClass_fooIOO_calls);
359 a.l = (jobject)8;
360 b.i = 0;
361 c.l = (jobject)NULL;
362 d.l = (jobject)16;
363 e = RunMethod(method, a, b, c, d);
364 ASSERT_EQ((jobject)8, e.l);
365 EXPECT_EQ(2, gJava_MyClass_fooIOO_calls);
366 b.i = 1;
367 e = RunMethod(method, a, b, c, d);
368 ASSERT_EQ((jobject)NULL, e.l);
369 EXPECT_EQ(3, gJava_MyClass_fooIOO_calls);
370 b.i = 2;
371 e = RunMethod(method, a, b, c, d);
372 ASSERT_EQ((jobject)16, e.l);
373 EXPECT_EQ(4, gJava_MyClass_fooIOO_calls);
374 a.l = (jobject)8;
375 b.i = 0;
376 c.l = (jobject)16;
377 d.l = (jobject)NULL;
378 e = RunMethod(method, a, b, c, d);
379 ASSERT_EQ((jobject)8, e.l);
380 EXPECT_EQ(5, gJava_MyClass_fooIOO_calls);
381 b.i = 1;
382 e = RunMethod(method, a, b, c, d);
383 ASSERT_EQ((jobject)16, e.l);
384 EXPECT_EQ(6, gJava_MyClass_fooIOO_calls);
385 b.i = 2;
386 e = RunMethod(method, a, b, c, d);
387 ASSERT_EQ((jobject)NULL, e.l);
388 EXPECT_EQ(7, gJava_MyClass_fooIOO_calls);
389}
390
391TEST_F(JniCompilerTest, CompileAndRunStaticIntObjectObjectMethod) {
Brian Carlstromf615a612011-07-23 12:50:34 -0700392 scoped_ptr<DexFile> dex(OpenDexFileBase64(kMyClassNativesDex));
Brian Carlstrom74eb46a2011-08-02 20:10:14 -0700393 PathClassLoader* class_loader = AllocPathClassLoader(dex.get());
Carl Shapiro419ec7b2011-08-03 14:48:33 -0700394
Brian Carlstrom74eb46a2011-08-02 20:10:14 -0700395 Class* klass = class_linker_->FindClass("LMyClass;", class_loader);
Carl Shapiro419ec7b2011-08-03 14:48:33 -0700396 ASSERT_TRUE(klass != NULL);
397
398 Method* method = klass->FindDirectMethod(
399 "fooSIOO",
400 "(ILjava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
401 ASSERT_TRUE(method != NULL);
Ian Rogersb033c752011-07-20 12:22:35 -0700402
403 Assembler jni_asm;
404 JniCompiler jni_compiler;
405 jni_compiler.Compile(&jni_asm, method);
406
407 // TODO: should really use JNIEnv to RegisterNative, but missing a
408 // complete story on this, so hack the RegisterNative below
409 method->RegisterNative(reinterpret_cast<void*>(&Java_MyClass_fooSIOO));
410
411 jvalue a, b, c, d;
412 a.i = 0;
413 b.l = (jobject)NULL;
414 c.l = (jobject)NULL;
415 EXPECT_EQ(0, gJava_MyClass_fooSIOO_calls);
416 d = RunMethod(method, a, b, c, a);
417 ASSERT_EQ((jobject)method->GetClass(), d.l);
418 EXPECT_EQ(1, gJava_MyClass_fooSIOO_calls);
419 a.i = 0;
420 b.l = (jobject)NULL;
421 c.l = (jobject)16;
422 d = RunMethod(method, a, b, c, a);
423 ASSERT_EQ((jobject)method->GetClass(), d.l);
424 EXPECT_EQ(2, gJava_MyClass_fooSIOO_calls);
425 a.i = 1;
426 d = RunMethod(method, a, b, c, a);
427 ASSERT_EQ((jobject)NULL, d.l);
428 EXPECT_EQ(3, gJava_MyClass_fooSIOO_calls);
429 a.i = 2;
430 d = RunMethod(method, a, b, c, a);
431 ASSERT_EQ((jobject)16, d.l);
432 EXPECT_EQ(4, gJava_MyClass_fooSIOO_calls);
433 a.i = 0;
434 b.l = (jobject)16;
435 c.l = (jobject)NULL;
436 d = RunMethod(method, a, b, c, a);
437 ASSERT_EQ((jobject)method->GetClass(), d.l);
438 EXPECT_EQ(5, gJava_MyClass_fooSIOO_calls);
439 a.i = 1;
440 d = RunMethod(method, a, b, c, a);
441 ASSERT_EQ((jobject)16, d.l);
442 EXPECT_EQ(6, gJava_MyClass_fooSIOO_calls);
443 a.i = 2;
444 d = RunMethod(method, a, b, c, a);
445 ASSERT_EQ((jobject)NULL, d.l);
446 EXPECT_EQ(7, gJava_MyClass_fooSIOO_calls);
447}
448
Ian Rogersdf20fe02011-07-20 20:34:16 -0700449TEST_F(JniCompilerTest, CompileAndRunStaticSynchronizedIntObjectObjectMethod) {
Brian Carlstromf615a612011-07-23 12:50:34 -0700450 scoped_ptr<DexFile> dex(OpenDexFileBase64(kMyClassNativesDex));
Brian Carlstrom74eb46a2011-08-02 20:10:14 -0700451 PathClassLoader* class_loader = AllocPathClassLoader(dex.get());
Carl Shapiro419ec7b2011-08-03 14:48:33 -0700452
Brian Carlstrom74eb46a2011-08-02 20:10:14 -0700453 Class* klass = class_linker_->FindClass("LMyClass;", class_loader);
Carl Shapiro419ec7b2011-08-03 14:48:33 -0700454 ASSERT_TRUE(klass != NULL);
455
456 Method* method = klass->FindDirectMethod(
457 "fooSSIOO",
458 "(ILjava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
459 ASSERT_TRUE(method != NULL);
Ian Rogersdf20fe02011-07-20 20:34:16 -0700460
461 Assembler jni_asm;
462 JniCompiler jni_compiler;
463 jni_compiler.Compile(&jni_asm, method);
464
465 // TODO: should really use JNIEnv to RegisterNative, but missing a
466 // complete story on this, so hack the RegisterNative below
467 method->RegisterNative(reinterpret_cast<void*>(&Java_MyClass_fooSSIOO));
468
469 jvalue a, b, c, d;
470 a.i = 0;
471 b.l = (jobject)NULL;
472 c.l = (jobject)NULL;
473 EXPECT_EQ(0, gJava_MyClass_fooSSIOO_calls);
474 d = RunMethod(method, a, b, c, a);
475 ASSERT_EQ((jobject)method->GetClass(), d.l);
476 EXPECT_EQ(1, gJava_MyClass_fooSSIOO_calls);
477 a.i = 0;
478 b.l = (jobject)NULL;
479 c.l = (jobject)16;
480 d = RunMethod(method, a, b, c, a);
481 ASSERT_EQ((jobject)method->GetClass(), d.l);
482 EXPECT_EQ(2, gJava_MyClass_fooSSIOO_calls);
483 a.i = 1;
484 d = RunMethod(method, a, b, c, a);
485 ASSERT_EQ((jobject)NULL, d.l);
486 EXPECT_EQ(3, gJava_MyClass_fooSSIOO_calls);
487 a.i = 2;
488 d = RunMethod(method, a, b, c, a);
489 ASSERT_EQ((jobject)16, d.l);
490 EXPECT_EQ(4, gJava_MyClass_fooSSIOO_calls);
491 a.i = 0;
492 b.l = (jobject)16;
493 c.l = (jobject)NULL;
494 d = RunMethod(method, a, b, c, a);
495 ASSERT_EQ((jobject)method->GetClass(), d.l);
496 EXPECT_EQ(5, gJava_MyClass_fooSSIOO_calls);
497 a.i = 1;
498 d = RunMethod(method, a, b, c, a);
499 ASSERT_EQ((jobject)16, d.l);
500 EXPECT_EQ(6, gJava_MyClass_fooSSIOO_calls);
501 a.i = 2;
502 d = RunMethod(method, a, b, c, a);
503 ASSERT_EQ((jobject)NULL, d.l);
504 EXPECT_EQ(7, gJava_MyClass_fooSSIOO_calls);
505}
506
Ian Rogers45a76cb2011-07-21 22:00:15 -0700507int gSuspendCounterHandler_calls;
508void SuspendCountHandler(Method** frame) {
Carl Shapiro8860c0e2011-08-04 17:36:16 -0700509 EXPECT_TRUE((*frame)->GetName()->Equals("fooI"));
Ian Rogers45a76cb2011-07-21 22:00:15 -0700510 gSuspendCounterHandler_calls++;
511 Thread::Current()->DecrementSuspendCount();
512}
Ian Rogers0d666d82011-08-14 16:03:46 -0700513TEST_F(JniCompilerTest, SuspendCountAcknowledgement) {
Brian Carlstromf615a612011-07-23 12:50:34 -0700514 scoped_ptr<DexFile> dex(OpenDexFileBase64(kMyClassNativesDex));
Brian Carlstrom74eb46a2011-08-02 20:10:14 -0700515 PathClassLoader* class_loader = AllocPathClassLoader(dex.get());
Carl Shapiro419ec7b2011-08-03 14:48:33 -0700516
Brian Carlstrom74eb46a2011-08-02 20:10:14 -0700517 Class* klass = class_linker_->FindClass("LMyClass;", class_loader);
Carl Shapiro419ec7b2011-08-03 14:48:33 -0700518 ASSERT_TRUE(klass != NULL);
519
520 Method* method = klass->FindVirtualMethod("fooI", "(I)I");
521 ASSERT_TRUE(method != NULL);
Ian Rogers45a76cb2011-07-21 22:00:15 -0700522
523 Assembler jni_asm;
524 JniCompiler jni_compiler;
525 jni_compiler.Compile(&jni_asm, method);
526
527 // TODO: should really use JNIEnv to RegisterNative, but missing a
528 // complete story on this, so hack the RegisterNative below
529 method->RegisterNative(reinterpret_cast<void*>(&Java_MyClass_fooI));
530 Thread::Current()->RegisterSuspendCountEntryPoint(&SuspendCountHandler);
531
532 gSuspendCounterHandler_calls = 0;
533 gJava_MyClass_fooI_calls = 0;
534 jvalue a, b, c;
535 a.l = (jobject)NULL;
536 b.i = 42;
537 c = RunMethod(method, a, b, a, a);
538 ASSERT_EQ(42, c.i);
539 EXPECT_EQ(1, gJava_MyClass_fooI_calls);
540 EXPECT_EQ(0, gSuspendCounterHandler_calls);
541 Thread::Current()->IncrementSuspendCount();
542 c = RunMethod(method, a, b, a, a);
543 ASSERT_EQ(42, c.i);
544 EXPECT_EQ(2, gJava_MyClass_fooI_calls);
545 EXPECT_EQ(1, gSuspendCounterHandler_calls);
546 c = RunMethod(method, a, b, a, a);
547 ASSERT_EQ(42, c.i);
548 EXPECT_EQ(3, gJava_MyClass_fooI_calls);
549 EXPECT_EQ(1, gSuspendCounterHandler_calls);
550}
551
552int gExceptionHandler_calls;
553void ExceptionHandler(Method** frame) {
Carl Shapiro8860c0e2011-08-04 17:36:16 -0700554 EXPECT_TRUE((*frame)->GetName()->Equals("foo"));
Ian Rogers45a76cb2011-07-21 22:00:15 -0700555 gExceptionHandler_calls++;
556 Thread::Current()->ClearException();
557}
558TEST_F(JniCompilerTest, ExceptionHandling) {
Brian Carlstromf615a612011-07-23 12:50:34 -0700559 scoped_ptr<DexFile> dex(OpenDexFileBase64(kMyClassNativesDex));
Brian Carlstrom74eb46a2011-08-02 20:10:14 -0700560 PathClassLoader* class_loader = AllocPathClassLoader(dex.get());
Carl Shapiro419ec7b2011-08-03 14:48:33 -0700561
Brian Carlstrom74eb46a2011-08-02 20:10:14 -0700562 Class* klass = class_linker_->FindClass("LMyClass;", class_loader);
Carl Shapiro419ec7b2011-08-03 14:48:33 -0700563 ASSERT_TRUE(klass != NULL);
564
565 Method* method = klass->FindVirtualMethod("foo", "()V");
566 ASSERT_TRUE(method != NULL);
Ian Rogers45a76cb2011-07-21 22:00:15 -0700567
568 Assembler jni_asm;
569 JniCompiler jni_compiler;
570 jni_compiler.Compile(&jni_asm, method);
571
572 // TODO: should really use JNIEnv to RegisterNative, but missing a
573 // complete story on this, so hack the RegisterNative below
574 method->RegisterNative(reinterpret_cast<void*>(&Java_MyClass_foo));
575 Thread::Current()->RegisterExceptionEntryPoint(&ExceptionHandler);
576
577 gExceptionHandler_calls = 0;
578 gJava_MyClass_foo_calls = 0;
579 jvalue a;
580 a.l = (jobject)NULL;
581 RunMethod(method, a, a, a, a);
582 EXPECT_EQ(1, gJava_MyClass_foo_calls);
583 EXPECT_EQ(0, gExceptionHandler_calls);
584 // TODO: create a real exception here
585 Thread::Current()->SetException(reinterpret_cast<Object*>(8));
586 RunMethod(method, a, a, a, a);
587 EXPECT_EQ(2, gJava_MyClass_foo_calls);
588 EXPECT_EQ(1, gExceptionHandler_calls);
589 RunMethod(method, a, a, a, a);
590 EXPECT_EQ(3, gJava_MyClass_foo_calls);
591 EXPECT_EQ(1, gExceptionHandler_calls);
592}
593
Ian Rogersb033c752011-07-20 12:22:35 -0700594} // namespace art