blob: d6017b56033a1434a24a8c5080b99945b4ba0d58 [file] [log] [blame]
Ian Rogersb033c752011-07-20 12:22:35 -07001// Copyright 2011 Google Inc. All Rights Reserved.
2// Author: irogers@google.com (Ian Rogers)
3
4#include <sys/mman.h>
Brian Carlstrom578bbdc2011-07-21 14:07:47 -07005
6#include "assembler.h"
7#include "class_linker.h"
8#include "common_test.h"
9#include "dex_file.h"
10#include "jni_compiler.h"
11#include "runtime.h"
12#include "thread.h"
Ian Rogersb033c752011-07-20 12:22:35 -070013#include "gtest/gtest.h"
14
15namespace art {
16
Brian Carlstrom578bbdc2011-07-21 14:07:47 -070017class JniCompilerTest : public RuntimeTest {
Ian Rogersb033c752011-07-20 12:22:35 -070018 protected:
19 virtual void SetUp() {
Brian Carlstrom578bbdc2011-07-21 14:07:47 -070020 RuntimeTest::SetUp();
Ian Rogersb033c752011-07-20 12:22:35 -070021 // Create thunk code that performs the native to managed transition
22 thunk_code_size_ = 4096;
23 thunk_ = mmap(NULL, thunk_code_size_, PROT_READ | PROT_WRITE | PROT_EXEC,
24 MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
25 CHECK_NE(MAP_FAILED, thunk_);
26 Assembler thk_asm;
27 // TODO: shouldn't have machine specific code in a general purpose file
28#if defined(__i386__)
29 thk_asm.pushl(EDI); // preserve EDI
30 thk_asm.movl(EAX, Address(ESP, 8)); // EAX = method->GetCode()
31 thk_asm.movl(EDI, Address(ESP, 12)); // EDI = method
32 thk_asm.pushl(Immediate(0)); // push pad
33 thk_asm.pushl(Immediate(0)); // push pad
Carl Shapiroe2d373e2011-07-25 15:20:06 -070034 thk_asm.pushl(Address(ESP, 44)); // push pad or jlong high
35 thk_asm.pushl(Address(ESP, 44)); // push jint or jlong low
36 thk_asm.pushl(Address(ESP, 44)); // push jint or jlong high
37 thk_asm.pushl(Address(ESP, 44)); // push jint or jlong low
38 thk_asm.pushl(Address(ESP, 44)); // push jobject
Ian Rogersb033c752011-07-20 12:22:35 -070039 thk_asm.call(EAX); // Continue in method->GetCode()
40 thk_asm.addl(ESP, Immediate(28)); // pop arguments
41 thk_asm.popl(EDI); // restore EDI
42 thk_asm.ret();
Carl Shapiroe2d373e2011-07-25 15:20:06 -070043#elif defined(__arm__)
44 thk_asm.AddConstant(SP, -32); // Build frame
Brian Carlstrom8ecd08c2011-07-27 17:50:51 -070045 thk_asm.StoreToOffset(kStoreWord, LR, SP, 28); // Spill link register
46 thk_asm.StoreToOffset(kStoreWord, R9, SP, 24); // Spill R9
47 thk_asm.mov(R12, ShifterOperand(R0)); // R12 = method->GetCode()
48 thk_asm.mov(R0, ShifterOperand(R1)); // R0 = method
49 thk_asm.mov(R9, ShifterOperand(R2)); // R9 = Thread::Current()
50 thk_asm.mov(R1, ShifterOperand(R3)); // R1 = arg1 (jint/jlong low)
51 thk_asm.LoadFromOffset(kLoadWord, R3, SP, 44); // R3 = arg5 (pad/jlong high)
Carl Shapiroe2d373e2011-07-25 15:20:06 -070052 thk_asm.StoreToOffset(kStoreWord, R3, SP, 4);
Brian Carlstrom8ecd08c2011-07-27 17:50:51 -070053 thk_asm.LoadFromOffset(kLoadWord, R3, SP, 40); // R3 = arg4 (jint/jlong low)
Carl Shapiroe2d373e2011-07-25 15:20:06 -070054 thk_asm.StoreToOffset(kStoreWord, R3, SP, 0);
Brian Carlstrom8ecd08c2011-07-27 17:50:51 -070055 thk_asm.LoadFromOffset(kLoadWord, R3, SP, 36); // R3 = arg3 (jint/jlong high)
56 thk_asm.LoadFromOffset(kLoadWord, R2, SP, 32); // R2 = arg2 (jint/jlong high)
Carl Shapiroe2d373e2011-07-25 15:20:06 -070057 thk_asm.blx(R12); // Branch and link R12
Brian Carlstrom8ecd08c2011-07-27 17:50:51 -070058 thk_asm.LoadFromOffset(kLoadWord, LR, SP, 28); // Fill link register
59 thk_asm.LoadFromOffset(kLoadWord, R9, SP, 24); // Fill R9
Carl Shapiroe2d373e2011-07-25 15:20:06 -070060 thk_asm.AddConstant(SP, 32); // Remove frame
61 thk_asm.mov(PC, ShifterOperand(LR)); // Return
Ian Rogersb033c752011-07-20 12:22:35 -070062#else
Carl Shapiroe2d373e2011-07-25 15:20:06 -070063#error Unimplemented
Ian Rogersb033c752011-07-20 12:22:35 -070064#endif
65 size_t cs = thk_asm.CodeSize();
66 MemoryRegion code(thunk_, cs);
67 thk_asm.FinalizeInstructions(code);
68 thunk_entry1_ = reinterpret_cast<jint (*)(const void*, art::Method*,
Carl Shapiroe2d373e2011-07-25 15:20:06 -070069 Thread*, jobject, jint, jint,
70 jint)
Ian Rogersb033c752011-07-20 12:22:35 -070071 >(code.pointer());
72 thunk_entry2_ = reinterpret_cast<jdouble (*)(const void*, art::Method*,
Carl Shapiroe2d373e2011-07-25 15:20:06 -070073 Thread*, jobject, jdouble,
74 jdouble)
Ian Rogersb033c752011-07-20 12:22:35 -070075 >(code.pointer());
76 }
77
78 virtual void TearDown() {
79 // Release thunk code
80 CHECK(runtime_->DetachCurrentThread());
81 CHECK_EQ(0, munmap(thunk_, thunk_code_size_));
82 }
83
84 // Run generated code associated with method passing and returning int size
85 // arguments
86 jvalue RunMethod(Method* method, jvalue a, jvalue b, jvalue c, jvalue d) {
87 jvalue result;
88 // sanity checks
89 EXPECT_NE(static_cast<void*>(NULL), method->GetCode());
90 EXPECT_EQ(0u, Thread::Current()->NumShbHandles());
91 EXPECT_EQ(Thread::kRunnable, Thread::Current()->GetState());
92 // perform call
Carl Shapiroe2d373e2011-07-25 15:20:06 -070093 result.i = (*thunk_entry1_)(method->GetCode(), method, Thread::Current(),
94 a.l, b.i, c.i, d.i);
Ian Rogersb033c752011-07-20 12:22:35 -070095 // sanity check post-call
96 EXPECT_EQ(0u, Thread::Current()->NumShbHandles());
97 EXPECT_EQ(Thread::kRunnable, Thread::Current()->GetState());
98 return result;
99 }
100
101 // Run generated code associated with method passing and returning double size
102 // arguments
103 jvalue RunMethodD(Method* method, jvalue a, jvalue b, jvalue c) {
104 jvalue result;
105 // sanity checks
106 EXPECT_NE(static_cast<void*>(NULL), method->GetCode());
107 EXPECT_EQ(0u, Thread::Current()->NumShbHandles());
108 EXPECT_EQ(Thread::kRunnable, Thread::Current()->GetState());
109 // perform call
Carl Shapiroe2d373e2011-07-25 15:20:06 -0700110 result.d = (*thunk_entry2_)(method->GetCode(), method, Thread::Current(),
111 a.l, b.d, c.d);
Ian Rogersb033c752011-07-20 12:22:35 -0700112 // sanity check post-call
113 EXPECT_EQ(0u, Thread::Current()->NumShbHandles());
114 EXPECT_EQ(Thread::kRunnable, Thread::Current()->GetState());
115 return result;
116 }
117
Ian Rogersb033c752011-07-20 12:22:35 -0700118 void* thunk_;
119 size_t thunk_code_size_;
Carl Shapiroe2d373e2011-07-25 15:20:06 -0700120 jint (*thunk_entry1_)(const void*, Method*, Thread*, jobject, jint, jint,
121 jint);
122 jdouble (*thunk_entry2_)(const void*, Method*, Thread*, jobject, jdouble,
123 jdouble);
Ian Rogersb033c752011-07-20 12:22:35 -0700124};
125
126int gJava_MyClass_foo_calls = 0;
127void Java_MyClass_foo(JNIEnv*, jobject) {
128 EXPECT_EQ(1u, Thread::Current()->NumShbHandles());
129 EXPECT_EQ(Thread::kNative, Thread::Current()->GetState());
130 gJava_MyClass_foo_calls++;
131}
132
133int gJava_MyClass_fooI_calls = 0;
134jint Java_MyClass_fooI(JNIEnv*, jobject, jint x) {
135 EXPECT_EQ(1u, Thread::Current()->NumShbHandles());
136 EXPECT_EQ(Thread::kNative, Thread::Current()->GetState());
137 gJava_MyClass_fooI_calls++;
138 return x;
139}
140
141int gJava_MyClass_fooII_calls = 0;
142jint Java_MyClass_fooII(JNIEnv*, jobject, jint x, jint y) {
143 EXPECT_EQ(1u, Thread::Current()->NumShbHandles());
144 EXPECT_EQ(Thread::kNative, Thread::Current()->GetState());
145 gJava_MyClass_fooII_calls++;
146 return x - y; // non-commutative operator
147}
148
149int gJava_MyClass_fooDD_calls = 0;
150jdouble Java_MyClass_fooDD(JNIEnv*, jobject, jdouble x, jdouble y) {
151 EXPECT_EQ(1u, Thread::Current()->NumShbHandles());
152 EXPECT_EQ(Thread::kNative, Thread::Current()->GetState());
153 gJava_MyClass_fooDD_calls++;
154 return x - y; // non-commutative operator
155}
156
157int gJava_MyClass_fooIOO_calls = 0;
158jobject Java_MyClass_fooIOO(JNIEnv*, jobject thisObject, jint x, jobject y,
159 jobject z) {
160 EXPECT_EQ(3u, Thread::Current()->NumShbHandles());
161 EXPECT_EQ(Thread::kNative, Thread::Current()->GetState());
162 gJava_MyClass_fooIOO_calls++;
163 switch (x) {
164 case 1:
165 return y;
166 case 2:
167 return z;
168 default:
169 return thisObject;
170 }
171}
172
173int gJava_MyClass_fooSIOO_calls = 0;
174jobject Java_MyClass_fooSIOO(JNIEnv*, jclass klass, jint x, jobject y,
175 jobject z) {
176 EXPECT_EQ(3u, Thread::Current()->NumShbHandles());
177 EXPECT_EQ(Thread::kNative, Thread::Current()->GetState());
178 gJava_MyClass_fooSIOO_calls++;
179 switch (x) {
180 case 1:
181 return y;
182 case 2:
183 return z;
184 default:
185 return klass;
186 }
187}
188
Ian Rogersdf20fe02011-07-20 20:34:16 -0700189int gJava_MyClass_fooSSIOO_calls = 0;
190jobject Java_MyClass_fooSSIOO(JNIEnv*, jclass klass, jint x, jobject y,
191 jobject z) {
192 EXPECT_EQ(3u, Thread::Current()->NumShbHandles());
193 EXPECT_EQ(Thread::kNative, Thread::Current()->GetState());
194 gJava_MyClass_fooSSIOO_calls++;
195 switch (x) {
196 case 1:
197 return y;
198 case 2:
199 return z;
200 default:
201 return klass;
202 }
203}
204
Ian Rogersb033c752011-07-20 12:22:35 -0700205TEST_F(JniCompilerTest, CompileAndRunNoArgMethod) {
Brian Carlstromf615a612011-07-23 12:50:34 -0700206 scoped_ptr<DexFile> dex(OpenDexFileBase64(kMyClassNativesDex));
Carl Shapiro7a909592011-07-24 19:21:59 -0700207 class_linker_->RegisterDexFile(dex.get());
208 Class* klass = class_linker_->FindClass("LMyClass;", NULL, dex.get());
Ian Rogersb033c752011-07-20 12:22:35 -0700209 Method* method = klass->FindVirtualMethod("foo");
210
211 Assembler jni_asm;
212 JniCompiler jni_compiler;
213 jni_compiler.Compile(&jni_asm, method);
214
215 // TODO: should really use JNIEnv to RegisterNative, but missing a
216 // complete story on this, so hack the RegisterNative below
217 // JNIEnv* env = Thread::Current()->GetJniEnv();
218 // JNINativeMethod methods[] = {{"foo", "()V", (void*)&Java_MyClass_foo}};
219 method->RegisterNative(reinterpret_cast<void*>(&Java_MyClass_foo));
220
221 jvalue a;
222 a.l = (jobject)NULL;
Ian Rogers45a76cb2011-07-21 22:00:15 -0700223 gJava_MyClass_foo_calls = 0;
Ian Rogersb033c752011-07-20 12:22:35 -0700224 RunMethod(method, a, a, a, a);
225 EXPECT_EQ(1, gJava_MyClass_foo_calls);
226 RunMethod(method, a, a, a, a);
227 EXPECT_EQ(2, gJava_MyClass_foo_calls);
228}
229
230TEST_F(JniCompilerTest, CompileAndRunIntMethod) {
Brian Carlstromf615a612011-07-23 12:50:34 -0700231 scoped_ptr<DexFile> dex(OpenDexFileBase64(kMyClassNativesDex));
Carl Shapiro7a909592011-07-24 19:21:59 -0700232 class_linker_->RegisterDexFile(dex.get());
233 Class* klass = class_linker_->FindClass("LMyClass;", NULL, dex.get());
Ian Rogersb033c752011-07-20 12:22:35 -0700234 Method* method = klass->FindVirtualMethod("fooI");
235
236 Assembler jni_asm;
237 JniCompiler jni_compiler;
238 jni_compiler.Compile(&jni_asm, method);
239
240 // TODO: should really use JNIEnv to RegisterNative, but missing a
241 // complete story on this, so hack the RegisterNative below
242 method->RegisterNative(reinterpret_cast<void*>(&Java_MyClass_fooI));
243
244 jvalue a, b, c;
245 a.l = (jobject)NULL;
246 b.i = 42;
247 EXPECT_EQ(0, gJava_MyClass_fooI_calls);
248 c = RunMethod(method, a, b, a, a);
249 ASSERT_EQ(42, c.i);
250 EXPECT_EQ(1, gJava_MyClass_fooI_calls);
251 b.i = 0xCAFED00D;
252 c = RunMethod(method, a, b, a, a);
253 ASSERT_EQ((jint)0xCAFED00D, c.i);
254 EXPECT_EQ(2, gJava_MyClass_fooI_calls);
255}
256
257TEST_F(JniCompilerTest, CompileAndRunIntIntMethod) {
Brian Carlstromf615a612011-07-23 12:50:34 -0700258 scoped_ptr<DexFile> dex(OpenDexFileBase64(kMyClassNativesDex));
Carl Shapiro7a909592011-07-24 19:21:59 -0700259 class_linker_->RegisterDexFile(dex.get());
260 Class* klass = class_linker_->FindClass("LMyClass;", NULL, dex.get());
Ian Rogersb033c752011-07-20 12:22:35 -0700261 Method* method = klass->FindVirtualMethod("fooII");
262
263 Assembler jni_asm;
264 JniCompiler jni_compiler;
265 jni_compiler.Compile(&jni_asm, method);
266
267 // TODO: should really use JNIEnv to RegisterNative, but missing a
268 // complete story on this, so hack the RegisterNative below
269 method->RegisterNative(reinterpret_cast<void*>(&Java_MyClass_fooII));
270
271 jvalue a, b, c, d;
272 a.l = (jobject)NULL;
273 b.i = 99;
274 c.i = 10;
275 EXPECT_EQ(0, gJava_MyClass_fooII_calls);
276 d = RunMethod(method, a, b, c, a);
277 ASSERT_EQ(99 - 10, d.i);
278 EXPECT_EQ(1, gJava_MyClass_fooII_calls);
279 b.i = 0xCAFEBABE;
280 c.i = 0xCAFED00D;
281 d = RunMethod(method, a, b, c, a);
282 ASSERT_EQ((jint)(0xCAFEBABE - 0xCAFED00D), d.i);
283 EXPECT_EQ(2, gJava_MyClass_fooII_calls);
284}
285
286
287TEST_F(JniCompilerTest, CompileAndRunDoubleDoubleMethod) {
Brian Carlstromf615a612011-07-23 12:50:34 -0700288 scoped_ptr<DexFile> dex(OpenDexFileBase64(kMyClassNativesDex));
Carl Shapiro7a909592011-07-24 19:21:59 -0700289 class_linker_->RegisterDexFile(dex.get());
290 Class* klass = class_linker_->FindClass("LMyClass;", NULL, dex.get());
Ian Rogersb033c752011-07-20 12:22:35 -0700291 Method* method = klass->FindVirtualMethod("fooDD");
292
293 Assembler jni_asm;
294 JniCompiler jni_compiler;
295 jni_compiler.Compile(&jni_asm, method);
296
297 // TODO: should really use JNIEnv to RegisterNative, but missing a
298 // complete story on this, so hack the RegisterNative below
299 method->RegisterNative(reinterpret_cast<void*>(&Java_MyClass_fooDD));
300
301 jvalue a, b, c, d;
302 a.l = (jobject)NULL;
303 b.d = 99;
304 c.d = 10;
305 EXPECT_EQ(0, gJava_MyClass_fooDD_calls);
306 d = RunMethodD(method, a, b, c);
307 ASSERT_EQ(b.d - c.d, d.d);
308 EXPECT_EQ(1, gJava_MyClass_fooDD_calls);
309 b.d = 3.14159265358979323846;
310 c.d = 0.69314718055994530942;
311 d = RunMethodD(method, a, b, c);
312 ASSERT_EQ(b.d - c.d, d.d);
313 EXPECT_EQ(2, gJava_MyClass_fooDD_calls);
314}
315
316TEST_F(JniCompilerTest, CompileAndRunIntObjectObjectMethod) {
Brian Carlstromf615a612011-07-23 12:50:34 -0700317 scoped_ptr<DexFile> dex(OpenDexFileBase64(kMyClassNativesDex));
Carl Shapiro7a909592011-07-24 19:21:59 -0700318 class_linker_->RegisterDexFile(dex.get());
319 Class* klass = class_linker_->FindClass("LMyClass;", NULL, dex.get());
Ian Rogersb033c752011-07-20 12:22:35 -0700320 Method* method = klass->FindVirtualMethod("fooIOO");
321
322 Assembler jni_asm;
323 JniCompiler jni_compiler;
324 jni_compiler.Compile(&jni_asm, method);
325
326 // TODO: should really use JNIEnv to RegisterNative, but missing a
327 // complete story on this, so hack the RegisterNative below
328 method->RegisterNative(reinterpret_cast<void*>(&Java_MyClass_fooIOO));
329
330 jvalue a, b, c, d, e;
331 a.l = (jobject)NULL;
332 b.i = 0;
333 c.l = (jobject)NULL;
334 d.l = (jobject)NULL;
335 EXPECT_EQ(0, gJava_MyClass_fooIOO_calls);
336 e = RunMethod(method, a, b, c, d);
337 ASSERT_EQ((jobject)NULL, e.l);
338 EXPECT_EQ(1, gJava_MyClass_fooIOO_calls);
339 a.l = (jobject)8;
340 b.i = 0;
341 c.l = (jobject)NULL;
342 d.l = (jobject)16;
343 e = RunMethod(method, a, b, c, d);
344 ASSERT_EQ((jobject)8, e.l);
345 EXPECT_EQ(2, gJava_MyClass_fooIOO_calls);
346 b.i = 1;
347 e = RunMethod(method, a, b, c, d);
348 ASSERT_EQ((jobject)NULL, e.l);
349 EXPECT_EQ(3, gJava_MyClass_fooIOO_calls);
350 b.i = 2;
351 e = RunMethod(method, a, b, c, d);
352 ASSERT_EQ((jobject)16, e.l);
353 EXPECT_EQ(4, gJava_MyClass_fooIOO_calls);
354 a.l = (jobject)8;
355 b.i = 0;
356 c.l = (jobject)16;
357 d.l = (jobject)NULL;
358 e = RunMethod(method, a, b, c, d);
359 ASSERT_EQ((jobject)8, e.l);
360 EXPECT_EQ(5, gJava_MyClass_fooIOO_calls);
361 b.i = 1;
362 e = RunMethod(method, a, b, c, d);
363 ASSERT_EQ((jobject)16, e.l);
364 EXPECT_EQ(6, gJava_MyClass_fooIOO_calls);
365 b.i = 2;
366 e = RunMethod(method, a, b, c, d);
367 ASSERT_EQ((jobject)NULL, e.l);
368 EXPECT_EQ(7, gJava_MyClass_fooIOO_calls);
369}
370
371TEST_F(JniCompilerTest, CompileAndRunStaticIntObjectObjectMethod) {
Brian Carlstromf615a612011-07-23 12:50:34 -0700372 scoped_ptr<DexFile> dex(OpenDexFileBase64(kMyClassNativesDex));
Carl Shapiro7a909592011-07-24 19:21:59 -0700373 class_linker_->RegisterDexFile(dex.get());
374 Class* klass = class_linker_->FindClass("LMyClass;", NULL, dex.get());
Ian Rogersb033c752011-07-20 12:22:35 -0700375 Method* method = klass->FindDirectMethod("fooSIOO");
376
377 Assembler jni_asm;
378 JniCompiler jni_compiler;
379 jni_compiler.Compile(&jni_asm, method);
380
381 // TODO: should really use JNIEnv to RegisterNative, but missing a
382 // complete story on this, so hack the RegisterNative below
383 method->RegisterNative(reinterpret_cast<void*>(&Java_MyClass_fooSIOO));
384
385 jvalue a, b, c, d;
386 a.i = 0;
387 b.l = (jobject)NULL;
388 c.l = (jobject)NULL;
389 EXPECT_EQ(0, gJava_MyClass_fooSIOO_calls);
390 d = RunMethod(method, a, b, c, a);
391 ASSERT_EQ((jobject)method->GetClass(), d.l);
392 EXPECT_EQ(1, gJava_MyClass_fooSIOO_calls);
393 a.i = 0;
394 b.l = (jobject)NULL;
395 c.l = (jobject)16;
396 d = RunMethod(method, a, b, c, a);
397 ASSERT_EQ((jobject)method->GetClass(), d.l);
398 EXPECT_EQ(2, gJava_MyClass_fooSIOO_calls);
399 a.i = 1;
400 d = RunMethod(method, a, b, c, a);
401 ASSERT_EQ((jobject)NULL, d.l);
402 EXPECT_EQ(3, gJava_MyClass_fooSIOO_calls);
403 a.i = 2;
404 d = RunMethod(method, a, b, c, a);
405 ASSERT_EQ((jobject)16, d.l);
406 EXPECT_EQ(4, gJava_MyClass_fooSIOO_calls);
407 a.i = 0;
408 b.l = (jobject)16;
409 c.l = (jobject)NULL;
410 d = RunMethod(method, a, b, c, a);
411 ASSERT_EQ((jobject)method->GetClass(), d.l);
412 EXPECT_EQ(5, gJava_MyClass_fooSIOO_calls);
413 a.i = 1;
414 d = RunMethod(method, a, b, c, a);
415 ASSERT_EQ((jobject)16, d.l);
416 EXPECT_EQ(6, gJava_MyClass_fooSIOO_calls);
417 a.i = 2;
418 d = RunMethod(method, a, b, c, a);
419 ASSERT_EQ((jobject)NULL, d.l);
420 EXPECT_EQ(7, gJava_MyClass_fooSIOO_calls);
421}
422
Ian Rogersdf20fe02011-07-20 20:34:16 -0700423TEST_F(JniCompilerTest, CompileAndRunStaticSynchronizedIntObjectObjectMethod) {
Brian Carlstromf615a612011-07-23 12:50:34 -0700424 scoped_ptr<DexFile> dex(OpenDexFileBase64(kMyClassNativesDex));
Carl Shapiro7a909592011-07-24 19:21:59 -0700425 class_linker_->RegisterDexFile(dex.get());
426 Class* klass = class_linker_->FindClass("LMyClass;", NULL, dex.get());
Ian Rogersdf20fe02011-07-20 20:34:16 -0700427 Method* method = klass->FindDirectMethod("fooSSIOO");
428
429 Assembler jni_asm;
430 JniCompiler jni_compiler;
431 jni_compiler.Compile(&jni_asm, method);
432
433 // TODO: should really use JNIEnv to RegisterNative, but missing a
434 // complete story on this, so hack the RegisterNative below
435 method->RegisterNative(reinterpret_cast<void*>(&Java_MyClass_fooSSIOO));
436
437 jvalue a, b, c, d;
438 a.i = 0;
439 b.l = (jobject)NULL;
440 c.l = (jobject)NULL;
441 EXPECT_EQ(0, gJava_MyClass_fooSSIOO_calls);
442 d = RunMethod(method, a, b, c, a);
443 ASSERT_EQ((jobject)method->GetClass(), d.l);
444 EXPECT_EQ(1, gJava_MyClass_fooSSIOO_calls);
445 a.i = 0;
446 b.l = (jobject)NULL;
447 c.l = (jobject)16;
448 d = RunMethod(method, a, b, c, a);
449 ASSERT_EQ((jobject)method->GetClass(), d.l);
450 EXPECT_EQ(2, gJava_MyClass_fooSSIOO_calls);
451 a.i = 1;
452 d = RunMethod(method, a, b, c, a);
453 ASSERT_EQ((jobject)NULL, d.l);
454 EXPECT_EQ(3, gJava_MyClass_fooSSIOO_calls);
455 a.i = 2;
456 d = RunMethod(method, a, b, c, a);
457 ASSERT_EQ((jobject)16, d.l);
458 EXPECT_EQ(4, gJava_MyClass_fooSSIOO_calls);
459 a.i = 0;
460 b.l = (jobject)16;
461 c.l = (jobject)NULL;
462 d = RunMethod(method, a, b, c, a);
463 ASSERT_EQ((jobject)method->GetClass(), d.l);
464 EXPECT_EQ(5, gJava_MyClass_fooSSIOO_calls);
465 a.i = 1;
466 d = RunMethod(method, a, b, c, a);
467 ASSERT_EQ((jobject)16, d.l);
468 EXPECT_EQ(6, gJava_MyClass_fooSSIOO_calls);
469 a.i = 2;
470 d = RunMethod(method, a, b, c, a);
471 ASSERT_EQ((jobject)NULL, d.l);
472 EXPECT_EQ(7, gJava_MyClass_fooSSIOO_calls);
473}
474
Ian Rogers45a76cb2011-07-21 22:00:15 -0700475int gSuspendCounterHandler_calls;
476void SuspendCountHandler(Method** frame) {
477 EXPECT_EQ(0, (*frame)->GetName().compare("fooI"));
478 gSuspendCounterHandler_calls++;
479 Thread::Current()->DecrementSuspendCount();
480}
481TEST_F(JniCompilerTest, SuspendCountAcknolewdgement) {
Brian Carlstromf615a612011-07-23 12:50:34 -0700482 scoped_ptr<DexFile> dex(OpenDexFileBase64(kMyClassNativesDex));
Carl Shapiro7a909592011-07-24 19:21:59 -0700483 class_linker_->RegisterDexFile(dex.get());
484 Class* klass = class_linker_->FindClass("LMyClass;", NULL, dex.get());
Ian Rogers45a76cb2011-07-21 22:00:15 -0700485 Method* method = klass->FindVirtualMethod("fooI");
486
487 Assembler jni_asm;
488 JniCompiler jni_compiler;
489 jni_compiler.Compile(&jni_asm, method);
490
491 // TODO: should really use JNIEnv to RegisterNative, but missing a
492 // complete story on this, so hack the RegisterNative below
493 method->RegisterNative(reinterpret_cast<void*>(&Java_MyClass_fooI));
494 Thread::Current()->RegisterSuspendCountEntryPoint(&SuspendCountHandler);
495
496 gSuspendCounterHandler_calls = 0;
497 gJava_MyClass_fooI_calls = 0;
498 jvalue a, b, c;
499 a.l = (jobject)NULL;
500 b.i = 42;
501 c = RunMethod(method, a, b, a, a);
502 ASSERT_EQ(42, c.i);
503 EXPECT_EQ(1, gJava_MyClass_fooI_calls);
504 EXPECT_EQ(0, gSuspendCounterHandler_calls);
505 Thread::Current()->IncrementSuspendCount();
506 c = RunMethod(method, a, b, a, a);
507 ASSERT_EQ(42, c.i);
508 EXPECT_EQ(2, gJava_MyClass_fooI_calls);
509 EXPECT_EQ(1, gSuspendCounterHandler_calls);
510 c = RunMethod(method, a, b, a, a);
511 ASSERT_EQ(42, c.i);
512 EXPECT_EQ(3, gJava_MyClass_fooI_calls);
513 EXPECT_EQ(1, gSuspendCounterHandler_calls);
514}
515
516int gExceptionHandler_calls;
517void ExceptionHandler(Method** frame) {
518 EXPECT_EQ(0, (*frame)->GetName().compare("foo"));
519 gExceptionHandler_calls++;
520 Thread::Current()->ClearException();
521}
522TEST_F(JniCompilerTest, ExceptionHandling) {
Brian Carlstromf615a612011-07-23 12:50:34 -0700523 scoped_ptr<DexFile> dex(OpenDexFileBase64(kMyClassNativesDex));
Carl Shapiro7a909592011-07-24 19:21:59 -0700524 class_linker_->RegisterDexFile(dex.get());
525 Class* klass = class_linker_->FindClass("LMyClass;", NULL, dex.get());
Ian Rogers45a76cb2011-07-21 22:00:15 -0700526 Method* method = klass->FindVirtualMethod("foo");
527
528 Assembler jni_asm;
529 JniCompiler jni_compiler;
530 jni_compiler.Compile(&jni_asm, method);
531
532 // TODO: should really use JNIEnv to RegisterNative, but missing a
533 // complete story on this, so hack the RegisterNative below
534 method->RegisterNative(reinterpret_cast<void*>(&Java_MyClass_foo));
535 Thread::Current()->RegisterExceptionEntryPoint(&ExceptionHandler);
536
537 gExceptionHandler_calls = 0;
538 gJava_MyClass_foo_calls = 0;
539 jvalue a;
540 a.l = (jobject)NULL;
541 RunMethod(method, a, a, a, a);
542 EXPECT_EQ(1, gJava_MyClass_foo_calls);
543 EXPECT_EQ(0, gExceptionHandler_calls);
544 // TODO: create a real exception here
545 Thread::Current()->SetException(reinterpret_cast<Object*>(8));
546 RunMethod(method, a, a, a, a);
547 EXPECT_EQ(2, gJava_MyClass_foo_calls);
548 EXPECT_EQ(1, gExceptionHandler_calls);
549 RunMethod(method, a, a, a, a);
550 EXPECT_EQ(3, gJava_MyClass_foo_calls);
551 EXPECT_EQ(1, gExceptionHandler_calls);
552}
553
Ian Rogersb033c752011-07-20 12:22:35 -0700554} // namespace art