blob: d4df48afcc65c01060e2eff10aefd2c2b55d8040 [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 Carlstromdb4d5402011-08-09 12:18:28 -070023 thunk_code_.reset(MemMap::Map(kPageSize,
24 PROT_READ | PROT_WRITE | PROT_EXEC,
25 MAP_ANONYMOUS | MAP_PRIVATE));
26 CHECK(thunk_code_ != NULL);
Ian Rogersb033c752011-07-20 12:22:35 -070027 Assembler thk_asm;
28 // TODO: shouldn't have machine specific code in a general purpose file
29#if defined(__i386__)
30 thk_asm.pushl(EDI); // preserve EDI
31 thk_asm.movl(EAX, Address(ESP, 8)); // EAX = method->GetCode()
32 thk_asm.movl(EDI, Address(ESP, 12)); // EDI = method
33 thk_asm.pushl(Immediate(0)); // push pad
34 thk_asm.pushl(Immediate(0)); // push pad
Carl Shapiroe2d373e2011-07-25 15:20:06 -070035 thk_asm.pushl(Address(ESP, 44)); // push pad or jlong high
36 thk_asm.pushl(Address(ESP, 44)); // push jint or jlong low
37 thk_asm.pushl(Address(ESP, 44)); // push jint or jlong high
38 thk_asm.pushl(Address(ESP, 44)); // push jint or jlong low
39 thk_asm.pushl(Address(ESP, 44)); // push jobject
Ian Rogersb033c752011-07-20 12:22:35 -070040 thk_asm.call(EAX); // Continue in method->GetCode()
41 thk_asm.addl(ESP, Immediate(28)); // pop arguments
42 thk_asm.popl(EDI); // restore EDI
43 thk_asm.ret();
Carl Shapiroe2d373e2011-07-25 15:20:06 -070044#elif defined(__arm__)
45 thk_asm.AddConstant(SP, -32); // Build frame
Brian Carlstrom8ecd08c2011-07-27 17:50:51 -070046 thk_asm.StoreToOffset(kStoreWord, LR, SP, 28); // Spill link register
47 thk_asm.StoreToOffset(kStoreWord, R9, SP, 24); // Spill R9
48 thk_asm.mov(R12, ShifterOperand(R0)); // R12 = method->GetCode()
49 thk_asm.mov(R0, ShifterOperand(R1)); // R0 = method
50 thk_asm.mov(R9, ShifterOperand(R2)); // R9 = Thread::Current()
51 thk_asm.mov(R1, ShifterOperand(R3)); // R1 = arg1 (jint/jlong low)
52 thk_asm.LoadFromOffset(kLoadWord, R3, SP, 44); // R3 = arg5 (pad/jlong high)
Carl Shapiroe2d373e2011-07-25 15:20:06 -070053 thk_asm.StoreToOffset(kStoreWord, R3, SP, 4);
Brian Carlstrom8ecd08c2011-07-27 17:50:51 -070054 thk_asm.LoadFromOffset(kLoadWord, R3, SP, 40); // R3 = arg4 (jint/jlong low)
Carl Shapiroe2d373e2011-07-25 15:20:06 -070055 thk_asm.StoreToOffset(kStoreWord, R3, SP, 0);
Brian Carlstrom8ecd08c2011-07-27 17:50:51 -070056 thk_asm.LoadFromOffset(kLoadWord, R3, SP, 36); // R3 = arg3 (jint/jlong high)
57 thk_asm.LoadFromOffset(kLoadWord, R2, SP, 32); // R2 = arg2 (jint/jlong high)
Carl Shapiroe2d373e2011-07-25 15:20:06 -070058 thk_asm.blx(R12); // Branch and link R12
Brian Carlstrom8ecd08c2011-07-27 17:50:51 -070059 thk_asm.LoadFromOffset(kLoadWord, LR, SP, 28); // Fill link register
60 thk_asm.LoadFromOffset(kLoadWord, R9, SP, 24); // Fill R9
Carl Shapiroe2d373e2011-07-25 15:20:06 -070061 thk_asm.AddConstant(SP, 32); // Remove frame
62 thk_asm.mov(PC, ShifterOperand(LR)); // Return
Ian Rogersb033c752011-07-20 12:22:35 -070063#else
Carl Shapiroe2d373e2011-07-25 15:20:06 -070064#error Unimplemented
Ian Rogersb033c752011-07-20 12:22:35 -070065#endif
66 size_t cs = thk_asm.CodeSize();
Brian Carlstromdb4d5402011-08-09 12:18:28 -070067 MemoryRegion code(thunk_code_->GetAddress(), cs);
Ian Rogersb033c752011-07-20 12:22:35 -070068 thk_asm.FinalizeInstructions(code);
69 thunk_entry1_ = reinterpret_cast<jint (*)(const void*, art::Method*,
Carl Shapiroe2d373e2011-07-25 15:20:06 -070070 Thread*, jobject, jint, jint,
71 jint)
Ian Rogersb033c752011-07-20 12:22:35 -070072 >(code.pointer());
73 thunk_entry2_ = reinterpret_cast<jdouble (*)(const void*, art::Method*,
Carl Shapiroe2d373e2011-07-25 15:20:06 -070074 Thread*, jobject, jdouble,
75 jdouble)
Ian Rogersb033c752011-07-20 12:22:35 -070076 >(code.pointer());
77 }
78
79 virtual void TearDown() {
80 // Release thunk code
81 CHECK(runtime_->DetachCurrentThread());
Ian Rogersb033c752011-07-20 12:22:35 -070082 }
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
Brian Carlstromdb4d5402011-08-09 12:18:28 -0700118 scoped_ptr<MemMap> thunk_code_;
Carl Shapiroe2d373e2011-07-25 15:20:06 -0700119 jint (*thunk_entry1_)(const void*, Method*, Thread*, jobject, jint, jint,
120 jint);
121 jdouble (*thunk_entry2_)(const void*, Method*, Thread*, jobject, jdouble,
122 jdouble);
Ian Rogersb033c752011-07-20 12:22:35 -0700123};
124
125int gJava_MyClass_foo_calls = 0;
126void Java_MyClass_foo(JNIEnv*, jobject) {
127 EXPECT_EQ(1u, Thread::Current()->NumShbHandles());
128 EXPECT_EQ(Thread::kNative, Thread::Current()->GetState());
129 gJava_MyClass_foo_calls++;
130}
131
132int gJava_MyClass_fooI_calls = 0;
133jint Java_MyClass_fooI(JNIEnv*, jobject, jint x) {
134 EXPECT_EQ(1u, Thread::Current()->NumShbHandles());
135 EXPECT_EQ(Thread::kNative, Thread::Current()->GetState());
136 gJava_MyClass_fooI_calls++;
137 return x;
138}
139
140int gJava_MyClass_fooII_calls = 0;
141jint Java_MyClass_fooII(JNIEnv*, jobject, jint x, jint y) {
142 EXPECT_EQ(1u, Thread::Current()->NumShbHandles());
143 EXPECT_EQ(Thread::kNative, Thread::Current()->GetState());
144 gJava_MyClass_fooII_calls++;
145 return x - y; // non-commutative operator
146}
147
148int gJava_MyClass_fooDD_calls = 0;
149jdouble Java_MyClass_fooDD(JNIEnv*, jobject, jdouble x, jdouble y) {
150 EXPECT_EQ(1u, Thread::Current()->NumShbHandles());
151 EXPECT_EQ(Thread::kNative, Thread::Current()->GetState());
152 gJava_MyClass_fooDD_calls++;
153 return x - y; // non-commutative operator
154}
155
156int gJava_MyClass_fooIOO_calls = 0;
157jobject Java_MyClass_fooIOO(JNIEnv*, jobject thisObject, jint x, jobject y,
158 jobject z) {
159 EXPECT_EQ(3u, Thread::Current()->NumShbHandles());
160 EXPECT_EQ(Thread::kNative, Thread::Current()->GetState());
161 gJava_MyClass_fooIOO_calls++;
162 switch (x) {
163 case 1:
164 return y;
165 case 2:
166 return z;
167 default:
168 return thisObject;
169 }
170}
171
172int gJava_MyClass_fooSIOO_calls = 0;
Elliott Hughes330304d2011-08-12 14:28:05 -0700173jobject Java_MyClass_fooSIOO(JNIEnv* env, jclass klass, jint x, jobject y,
Ian Rogersb033c752011-07-20 12:22:35 -0700174 jobject z) {
Elliott Hughes330304d2011-08-12 14:28:05 -0700175 EXPECT_EQ(Thread::Current()->GetJniEnv(), env);
Ian Rogersb033c752011-07-20 12:22:35 -0700176 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));
Brian Carlstrom74eb46a2011-08-02 20:10:14 -0700207 PathClassLoader* class_loader = AllocPathClassLoader(dex.get());
Carl Shapiro419ec7b2011-08-03 14:48:33 -0700208
Brian Carlstrom74eb46a2011-08-02 20:10:14 -0700209 Class* klass = class_linker_->FindClass("LMyClass;", class_loader);
Carl Shapiro419ec7b2011-08-03 14:48:33 -0700210 ASSERT_TRUE(klass != NULL);
211
212 Method* method = klass->FindVirtualMethod("foo", "()V");
213 ASSERT_TRUE(method != NULL);
Ian Rogersb033c752011-07-20 12:22:35 -0700214
215 Assembler jni_asm;
216 JniCompiler jni_compiler;
217 jni_compiler.Compile(&jni_asm, method);
218
219 // TODO: should really use JNIEnv to RegisterNative, but missing a
220 // complete story on this, so hack the RegisterNative below
221 // JNIEnv* env = Thread::Current()->GetJniEnv();
222 // JNINativeMethod methods[] = {{"foo", "()V", (void*)&Java_MyClass_foo}};
223 method->RegisterNative(reinterpret_cast<void*>(&Java_MyClass_foo));
224
225 jvalue a;
226 a.l = (jobject)NULL;
Ian Rogers45a76cb2011-07-21 22:00:15 -0700227 gJava_MyClass_foo_calls = 0;
Ian Rogersb033c752011-07-20 12:22:35 -0700228 RunMethod(method, a, a, a, a);
229 EXPECT_EQ(1, gJava_MyClass_foo_calls);
230 RunMethod(method, a, a, a, a);
231 EXPECT_EQ(2, gJava_MyClass_foo_calls);
232}
233
234TEST_F(JniCompilerTest, CompileAndRunIntMethod) {
Brian Carlstromf615a612011-07-23 12:50:34 -0700235 scoped_ptr<DexFile> dex(OpenDexFileBase64(kMyClassNativesDex));
Brian Carlstrom74eb46a2011-08-02 20:10:14 -0700236 PathClassLoader* class_loader = AllocPathClassLoader(dex.get());
Carl Shapiro419ec7b2011-08-03 14:48:33 -0700237
Brian Carlstrom74eb46a2011-08-02 20:10:14 -0700238 Class* klass = class_linker_->FindClass("LMyClass;", class_loader);
Carl Shapiro419ec7b2011-08-03 14:48:33 -0700239 ASSERT_TRUE(klass != NULL);
240
241 Method* method = klass->FindVirtualMethod("fooI", "(I)I");
242 ASSERT_TRUE(method != NULL);
Ian Rogersb033c752011-07-20 12:22:35 -0700243
244 Assembler jni_asm;
245 JniCompiler jni_compiler;
246 jni_compiler.Compile(&jni_asm, method);
247
248 // TODO: should really use JNIEnv to RegisterNative, but missing a
249 // complete story on this, so hack the RegisterNative below
250 method->RegisterNative(reinterpret_cast<void*>(&Java_MyClass_fooI));
251
252 jvalue a, b, c;
253 a.l = (jobject)NULL;
254 b.i = 42;
255 EXPECT_EQ(0, gJava_MyClass_fooI_calls);
256 c = RunMethod(method, a, b, a, a);
257 ASSERT_EQ(42, c.i);
258 EXPECT_EQ(1, gJava_MyClass_fooI_calls);
259 b.i = 0xCAFED00D;
260 c = RunMethod(method, a, b, a, a);
261 ASSERT_EQ((jint)0xCAFED00D, c.i);
262 EXPECT_EQ(2, gJava_MyClass_fooI_calls);
263}
264
265TEST_F(JniCompilerTest, CompileAndRunIntIntMethod) {
Brian Carlstromf615a612011-07-23 12:50:34 -0700266 scoped_ptr<DexFile> dex(OpenDexFileBase64(kMyClassNativesDex));
Brian Carlstrom74eb46a2011-08-02 20:10:14 -0700267 PathClassLoader* class_loader = AllocPathClassLoader(dex.get());
Carl Shapiro419ec7b2011-08-03 14:48:33 -0700268
Brian Carlstrom74eb46a2011-08-02 20:10:14 -0700269 Class* klass = class_linker_->FindClass("LMyClass;", class_loader);
Carl Shapiro419ec7b2011-08-03 14:48:33 -0700270 ASSERT_TRUE(klass != NULL);
271
272 Method* method = klass->FindVirtualMethod("fooII", "(II)I");
273 ASSERT_TRUE(method != NULL);
Ian Rogersb033c752011-07-20 12:22:35 -0700274
275 Assembler jni_asm;
276 JniCompiler jni_compiler;
277 jni_compiler.Compile(&jni_asm, method);
278
279 // TODO: should really use JNIEnv to RegisterNative, but missing a
280 // complete story on this, so hack the RegisterNative below
281 method->RegisterNative(reinterpret_cast<void*>(&Java_MyClass_fooII));
282
283 jvalue a, b, c, d;
284 a.l = (jobject)NULL;
285 b.i = 99;
286 c.i = 10;
287 EXPECT_EQ(0, gJava_MyClass_fooII_calls);
288 d = RunMethod(method, a, b, c, a);
289 ASSERT_EQ(99 - 10, d.i);
290 EXPECT_EQ(1, gJava_MyClass_fooII_calls);
291 b.i = 0xCAFEBABE;
292 c.i = 0xCAFED00D;
293 d = RunMethod(method, a, b, c, a);
294 ASSERT_EQ((jint)(0xCAFEBABE - 0xCAFED00D), d.i);
295 EXPECT_EQ(2, gJava_MyClass_fooII_calls);
296}
297
298
299TEST_F(JniCompilerTest, CompileAndRunDoubleDoubleMethod) {
Brian Carlstromf615a612011-07-23 12:50:34 -0700300 scoped_ptr<DexFile> dex(OpenDexFileBase64(kMyClassNativesDex));
Brian Carlstrom74eb46a2011-08-02 20:10:14 -0700301 PathClassLoader* class_loader = AllocPathClassLoader(dex.get());
Carl Shapiro419ec7b2011-08-03 14:48:33 -0700302
Brian Carlstrom74eb46a2011-08-02 20:10:14 -0700303 Class* klass = class_linker_->FindClass("LMyClass;", class_loader);
Carl Shapiro419ec7b2011-08-03 14:48:33 -0700304 ASSERT_TRUE(klass != NULL);
305
306 Method* method = klass->FindVirtualMethod("fooDD", "(DD)D");
307 ASSERT_TRUE(method != NULL);
Ian Rogersb033c752011-07-20 12:22:35 -0700308
309 Assembler jni_asm;
310 JniCompiler jni_compiler;
311 jni_compiler.Compile(&jni_asm, method);
312
313 // TODO: should really use JNIEnv to RegisterNative, but missing a
314 // complete story on this, so hack the RegisterNative below
315 method->RegisterNative(reinterpret_cast<void*>(&Java_MyClass_fooDD));
316
317 jvalue a, b, c, d;
318 a.l = (jobject)NULL;
319 b.d = 99;
320 c.d = 10;
321 EXPECT_EQ(0, gJava_MyClass_fooDD_calls);
322 d = RunMethodD(method, a, b, c);
323 ASSERT_EQ(b.d - c.d, d.d);
324 EXPECT_EQ(1, gJava_MyClass_fooDD_calls);
325 b.d = 3.14159265358979323846;
326 c.d = 0.69314718055994530942;
327 d = RunMethodD(method, a, b, c);
328 ASSERT_EQ(b.d - c.d, d.d);
329 EXPECT_EQ(2, gJava_MyClass_fooDD_calls);
330}
331
332TEST_F(JniCompilerTest, CompileAndRunIntObjectObjectMethod) {
Brian Carlstromf615a612011-07-23 12:50:34 -0700333 scoped_ptr<DexFile> dex(OpenDexFileBase64(kMyClassNativesDex));
Brian Carlstrom74eb46a2011-08-02 20:10:14 -0700334 PathClassLoader* class_loader = AllocPathClassLoader(dex.get());
Carl Shapiro419ec7b2011-08-03 14:48:33 -0700335
Brian Carlstrom74eb46a2011-08-02 20:10:14 -0700336 Class* klass = class_linker_->FindClass("LMyClass;", class_loader);
Carl Shapiro419ec7b2011-08-03 14:48:33 -0700337 ASSERT_TRUE(klass != NULL);
338
339 Method* method = klass->FindVirtualMethod(
340 "fooIOO",
341 "(ILjava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
342 ASSERT_TRUE(method != NULL);
Ian Rogersb033c752011-07-20 12:22:35 -0700343
344 Assembler jni_asm;
345 JniCompiler jni_compiler;
346 jni_compiler.Compile(&jni_asm, method);
347
348 // TODO: should really use JNIEnv to RegisterNative, but missing a
349 // complete story on this, so hack the RegisterNative below
350 method->RegisterNative(reinterpret_cast<void*>(&Java_MyClass_fooIOO));
351
352 jvalue a, b, c, d, e;
353 a.l = (jobject)NULL;
354 b.i = 0;
355 c.l = (jobject)NULL;
356 d.l = (jobject)NULL;
357 EXPECT_EQ(0, gJava_MyClass_fooIOO_calls);
358 e = RunMethod(method, a, b, c, d);
359 ASSERT_EQ((jobject)NULL, e.l);
360 EXPECT_EQ(1, gJava_MyClass_fooIOO_calls);
361 a.l = (jobject)8;
362 b.i = 0;
363 c.l = (jobject)NULL;
364 d.l = (jobject)16;
365 e = RunMethod(method, a, b, c, d);
366 ASSERT_EQ((jobject)8, e.l);
367 EXPECT_EQ(2, gJava_MyClass_fooIOO_calls);
368 b.i = 1;
369 e = RunMethod(method, a, b, c, d);
370 ASSERT_EQ((jobject)NULL, e.l);
371 EXPECT_EQ(3, gJava_MyClass_fooIOO_calls);
372 b.i = 2;
373 e = RunMethod(method, a, b, c, d);
374 ASSERT_EQ((jobject)16, e.l);
375 EXPECT_EQ(4, gJava_MyClass_fooIOO_calls);
376 a.l = (jobject)8;
377 b.i = 0;
378 c.l = (jobject)16;
379 d.l = (jobject)NULL;
380 e = RunMethod(method, a, b, c, d);
381 ASSERT_EQ((jobject)8, e.l);
382 EXPECT_EQ(5, gJava_MyClass_fooIOO_calls);
383 b.i = 1;
384 e = RunMethod(method, a, b, c, d);
385 ASSERT_EQ((jobject)16, e.l);
386 EXPECT_EQ(6, gJava_MyClass_fooIOO_calls);
387 b.i = 2;
388 e = RunMethod(method, a, b, c, d);
389 ASSERT_EQ((jobject)NULL, e.l);
390 EXPECT_EQ(7, gJava_MyClass_fooIOO_calls);
391}
392
393TEST_F(JniCompilerTest, CompileAndRunStaticIntObjectObjectMethod) {
Brian Carlstromf615a612011-07-23 12:50:34 -0700394 scoped_ptr<DexFile> dex(OpenDexFileBase64(kMyClassNativesDex));
Brian Carlstrom74eb46a2011-08-02 20:10:14 -0700395 PathClassLoader* class_loader = AllocPathClassLoader(dex.get());
Carl Shapiro419ec7b2011-08-03 14:48:33 -0700396
Brian Carlstrom74eb46a2011-08-02 20:10:14 -0700397 Class* klass = class_linker_->FindClass("LMyClass;", class_loader);
Carl Shapiro419ec7b2011-08-03 14:48:33 -0700398 ASSERT_TRUE(klass != NULL);
399
400 Method* method = klass->FindDirectMethod(
401 "fooSIOO",
402 "(ILjava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
403 ASSERT_TRUE(method != NULL);
Ian Rogersb033c752011-07-20 12:22:35 -0700404
405 Assembler jni_asm;
406 JniCompiler jni_compiler;
407 jni_compiler.Compile(&jni_asm, method);
408
409 // TODO: should really use JNIEnv to RegisterNative, but missing a
410 // complete story on this, so hack the RegisterNative below
411 method->RegisterNative(reinterpret_cast<void*>(&Java_MyClass_fooSIOO));
412
413 jvalue a, b, c, d;
414 a.i = 0;
415 b.l = (jobject)NULL;
416 c.l = (jobject)NULL;
417 EXPECT_EQ(0, gJava_MyClass_fooSIOO_calls);
418 d = RunMethod(method, a, b, c, a);
419 ASSERT_EQ((jobject)method->GetClass(), d.l);
420 EXPECT_EQ(1, gJava_MyClass_fooSIOO_calls);
421 a.i = 0;
422 b.l = (jobject)NULL;
423 c.l = (jobject)16;
424 d = RunMethod(method, a, b, c, a);
425 ASSERT_EQ((jobject)method->GetClass(), d.l);
426 EXPECT_EQ(2, gJava_MyClass_fooSIOO_calls);
427 a.i = 1;
428 d = RunMethod(method, a, b, c, a);
429 ASSERT_EQ((jobject)NULL, d.l);
430 EXPECT_EQ(3, gJava_MyClass_fooSIOO_calls);
431 a.i = 2;
432 d = RunMethod(method, a, b, c, a);
433 ASSERT_EQ((jobject)16, d.l);
434 EXPECT_EQ(4, gJava_MyClass_fooSIOO_calls);
435 a.i = 0;
436 b.l = (jobject)16;
437 c.l = (jobject)NULL;
438 d = RunMethod(method, a, b, c, a);
439 ASSERT_EQ((jobject)method->GetClass(), d.l);
440 EXPECT_EQ(5, gJava_MyClass_fooSIOO_calls);
441 a.i = 1;
442 d = RunMethod(method, a, b, c, a);
443 ASSERT_EQ((jobject)16, d.l);
444 EXPECT_EQ(6, gJava_MyClass_fooSIOO_calls);
445 a.i = 2;
446 d = RunMethod(method, a, b, c, a);
447 ASSERT_EQ((jobject)NULL, d.l);
448 EXPECT_EQ(7, gJava_MyClass_fooSIOO_calls);
449}
450
Ian Rogersdf20fe02011-07-20 20:34:16 -0700451TEST_F(JniCompilerTest, CompileAndRunStaticSynchronizedIntObjectObjectMethod) {
Brian Carlstromf615a612011-07-23 12:50:34 -0700452 scoped_ptr<DexFile> dex(OpenDexFileBase64(kMyClassNativesDex));
Brian Carlstrom74eb46a2011-08-02 20:10:14 -0700453 PathClassLoader* class_loader = AllocPathClassLoader(dex.get());
Carl Shapiro419ec7b2011-08-03 14:48:33 -0700454
Brian Carlstrom74eb46a2011-08-02 20:10:14 -0700455 Class* klass = class_linker_->FindClass("LMyClass;", class_loader);
Carl Shapiro419ec7b2011-08-03 14:48:33 -0700456 ASSERT_TRUE(klass != NULL);
457
458 Method* method = klass->FindDirectMethod(
459 "fooSSIOO",
460 "(ILjava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
461 ASSERT_TRUE(method != NULL);
Ian Rogersdf20fe02011-07-20 20:34:16 -0700462
463 Assembler jni_asm;
464 JniCompiler jni_compiler;
465 jni_compiler.Compile(&jni_asm, method);
466
467 // TODO: should really use JNIEnv to RegisterNative, but missing a
468 // complete story on this, so hack the RegisterNative below
469 method->RegisterNative(reinterpret_cast<void*>(&Java_MyClass_fooSSIOO));
470
471 jvalue a, b, c, d;
472 a.i = 0;
473 b.l = (jobject)NULL;
474 c.l = (jobject)NULL;
475 EXPECT_EQ(0, gJava_MyClass_fooSSIOO_calls);
476 d = RunMethod(method, a, b, c, a);
477 ASSERT_EQ((jobject)method->GetClass(), d.l);
478 EXPECT_EQ(1, gJava_MyClass_fooSSIOO_calls);
479 a.i = 0;
480 b.l = (jobject)NULL;
481 c.l = (jobject)16;
482 d = RunMethod(method, a, b, c, a);
483 ASSERT_EQ((jobject)method->GetClass(), d.l);
484 EXPECT_EQ(2, gJava_MyClass_fooSSIOO_calls);
485 a.i = 1;
486 d = RunMethod(method, a, b, c, a);
487 ASSERT_EQ((jobject)NULL, d.l);
488 EXPECT_EQ(3, gJava_MyClass_fooSSIOO_calls);
489 a.i = 2;
490 d = RunMethod(method, a, b, c, a);
491 ASSERT_EQ((jobject)16, d.l);
492 EXPECT_EQ(4, gJava_MyClass_fooSSIOO_calls);
493 a.i = 0;
494 b.l = (jobject)16;
495 c.l = (jobject)NULL;
496 d = RunMethod(method, a, b, c, a);
497 ASSERT_EQ((jobject)method->GetClass(), d.l);
498 EXPECT_EQ(5, gJava_MyClass_fooSSIOO_calls);
499 a.i = 1;
500 d = RunMethod(method, a, b, c, a);
501 ASSERT_EQ((jobject)16, d.l);
502 EXPECT_EQ(6, gJava_MyClass_fooSSIOO_calls);
503 a.i = 2;
504 d = RunMethod(method, a, b, c, a);
505 ASSERT_EQ((jobject)NULL, d.l);
506 EXPECT_EQ(7, gJava_MyClass_fooSSIOO_calls);
507}
508
Ian Rogers45a76cb2011-07-21 22:00:15 -0700509int gSuspendCounterHandler_calls;
510void SuspendCountHandler(Method** frame) {
Carl Shapiro8860c0e2011-08-04 17:36:16 -0700511 EXPECT_TRUE((*frame)->GetName()->Equals("fooI"));
Ian Rogers45a76cb2011-07-21 22:00:15 -0700512 gSuspendCounterHandler_calls++;
513 Thread::Current()->DecrementSuspendCount();
514}
Ian Rogers0d666d82011-08-14 16:03:46 -0700515TEST_F(JniCompilerTest, SuspendCountAcknowledgement) {
Brian Carlstromf615a612011-07-23 12:50:34 -0700516 scoped_ptr<DexFile> dex(OpenDexFileBase64(kMyClassNativesDex));
Brian Carlstrom74eb46a2011-08-02 20:10:14 -0700517 PathClassLoader* class_loader = AllocPathClassLoader(dex.get());
Carl Shapiro419ec7b2011-08-03 14:48:33 -0700518
Brian Carlstrom74eb46a2011-08-02 20:10:14 -0700519 Class* klass = class_linker_->FindClass("LMyClass;", class_loader);
Carl Shapiro419ec7b2011-08-03 14:48:33 -0700520 ASSERT_TRUE(klass != NULL);
521
522 Method* method = klass->FindVirtualMethod("fooI", "(I)I");
523 ASSERT_TRUE(method != NULL);
Ian Rogers45a76cb2011-07-21 22:00:15 -0700524
525 Assembler jni_asm;
526 JniCompiler jni_compiler;
527 jni_compiler.Compile(&jni_asm, method);
528
529 // TODO: should really use JNIEnv to RegisterNative, but missing a
530 // complete story on this, so hack the RegisterNative below
531 method->RegisterNative(reinterpret_cast<void*>(&Java_MyClass_fooI));
532 Thread::Current()->RegisterSuspendCountEntryPoint(&SuspendCountHandler);
533
534 gSuspendCounterHandler_calls = 0;
535 gJava_MyClass_fooI_calls = 0;
536 jvalue a, b, c;
537 a.l = (jobject)NULL;
538 b.i = 42;
539 c = RunMethod(method, a, b, a, a);
540 ASSERT_EQ(42, c.i);
541 EXPECT_EQ(1, gJava_MyClass_fooI_calls);
542 EXPECT_EQ(0, gSuspendCounterHandler_calls);
543 Thread::Current()->IncrementSuspendCount();
544 c = RunMethod(method, a, b, a, a);
545 ASSERT_EQ(42, c.i);
546 EXPECT_EQ(2, gJava_MyClass_fooI_calls);
547 EXPECT_EQ(1, gSuspendCounterHandler_calls);
548 c = RunMethod(method, a, b, a, a);
549 ASSERT_EQ(42, c.i);
550 EXPECT_EQ(3, gJava_MyClass_fooI_calls);
551 EXPECT_EQ(1, gSuspendCounterHandler_calls);
552}
553
554int gExceptionHandler_calls;
555void ExceptionHandler(Method** frame) {
Carl Shapiro8860c0e2011-08-04 17:36:16 -0700556 EXPECT_TRUE((*frame)->GetName()->Equals("foo"));
Ian Rogers45a76cb2011-07-21 22:00:15 -0700557 gExceptionHandler_calls++;
558 Thread::Current()->ClearException();
559}
560TEST_F(JniCompilerTest, ExceptionHandling) {
Brian Carlstromf615a612011-07-23 12:50:34 -0700561 scoped_ptr<DexFile> dex(OpenDexFileBase64(kMyClassNativesDex));
Brian Carlstrom74eb46a2011-08-02 20:10:14 -0700562 PathClassLoader* class_loader = AllocPathClassLoader(dex.get());
Carl Shapiro419ec7b2011-08-03 14:48:33 -0700563
Brian Carlstrom74eb46a2011-08-02 20:10:14 -0700564 Class* klass = class_linker_->FindClass("LMyClass;", class_loader);
Carl Shapiro419ec7b2011-08-03 14:48:33 -0700565 ASSERT_TRUE(klass != NULL);
566
567 Method* method = klass->FindVirtualMethod("foo", "()V");
568 ASSERT_TRUE(method != NULL);
Ian Rogers45a76cb2011-07-21 22:00:15 -0700569
570 Assembler jni_asm;
571 JniCompiler jni_compiler;
572 jni_compiler.Compile(&jni_asm, method);
573
574 // TODO: should really use JNIEnv to RegisterNative, but missing a
575 // complete story on this, so hack the RegisterNative below
576 method->RegisterNative(reinterpret_cast<void*>(&Java_MyClass_foo));
577 Thread::Current()->RegisterExceptionEntryPoint(&ExceptionHandler);
578
579 gExceptionHandler_calls = 0;
580 gJava_MyClass_foo_calls = 0;
581 jvalue a;
582 a.l = (jobject)NULL;
583 RunMethod(method, a, a, a, a);
584 EXPECT_EQ(1, gJava_MyClass_foo_calls);
585 EXPECT_EQ(0, gExceptionHandler_calls);
586 // TODO: create a real exception here
587 Thread::Current()->SetException(reinterpret_cast<Object*>(8));
588 RunMethod(method, a, a, a, a);
589 EXPECT_EQ(2, gJava_MyClass_foo_calls);
590 EXPECT_EQ(1, gExceptionHandler_calls);
591 RunMethod(method, a, a, a, a);
592 EXPECT_EQ(3, gJava_MyClass_foo_calls);
593 EXPECT_EQ(1, gExceptionHandler_calls);
594}
595
Ian Rogersb033c752011-07-20 12:22:35 -0700596} // namespace art