blob: 94a75980e1d72bfee23a2acb9eef537cfd0aabeb [file] [log] [blame]
Andreas Gampe525cde22014-04-22 15:44:50 -07001/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "common_runtime_test.h"
Andreas Gampe2ba8d4b2014-05-02 17:33:17 -070018#include "mirror/string-inl.h"
Andreas Gampe525cde22014-04-22 15:44:50 -070019
20#include <cstdio>
21
22namespace art {
23
24
25class StubTest : public CommonRuntimeTest {
26 protected:
27 // We need callee-save methods set up in the Runtime for exceptions.
28 void SetUp() OVERRIDE {
29 // Do the normal setup.
30 CommonRuntimeTest::SetUp();
31
32 {
33 // Create callee-save methods
34 ScopedObjectAccess soa(Thread::Current());
35 for (int i = 0; i < Runtime::kLastCalleeSaveType; i++) {
36 Runtime::CalleeSaveType type = Runtime::CalleeSaveType(i);
37 if (!runtime_->HasCalleeSaveMethod(type)) {
38 runtime_->SetCalleeSaveMethod(runtime_->CreateCalleeSaveMethod(kRuntimeISA, type), type);
39 }
40 }
41 }
42 }
43
Andreas Gampe00c1e6d2014-04-25 15:47:13 -070044 void SetUpRuntimeOptions(Runtime::Options *options) OVERRIDE {
45 // Use a smaller heap
46 for (std::pair<std::string, const void*>& pair : *options) {
47 if (pair.first.find("-Xmx") == 0) {
48 pair.first = "-Xmx4M"; // Smallest we can go.
49 }
50 }
51 }
Andreas Gampe525cde22014-04-22 15:44:50 -070052
53 size_t Invoke3(size_t arg0, size_t arg1, size_t arg2, uintptr_t code, Thread* self) {
54 // Push a transition back into managed code onto the linked list in thread.
55 ManagedStack fragment;
56 self->PushManagedStackFragment(&fragment);
57
58 size_t result;
59#if defined(__i386__)
60 // TODO: Set the thread?
61 __asm__ __volatile__(
62 "pushl $0\n\t" // Push nullptr to terminate quick stack
63 "call *%%edi\n\t" // Call the stub
64 "addl $4, %%esp" // Pop nullptr
65 : "=a" (result)
66 // Use the result from eax
67 : "a"(arg0), "c"(arg1), "d"(arg2), "D"(code)
68 // This places code into edi, arg0 into eax, arg1 into ecx, and arg2 into edx
69 : ); // clobber.
70 // TODO: Should we clobber the other registers? EBX gets clobbered by some of the stubs,
71 // but compilation fails when declaring that.
72#elif defined(__arm__)
73 __asm__ __volatile__(
Andreas Gampe00c1e6d2014-04-25 15:47:13 -070074 "push {r1-r12, lr}\n\t" // Save state, 13*4B = 52B
75 ".cfi_adjust_cfa_offset 52\n\t"
76 "sub sp, sp, #8\n\t" // +8B, so 16B aligned with nullptr
77 ".cfi_adjust_cfa_offset 8\n\t"
Andreas Gampe525cde22014-04-22 15:44:50 -070078 "mov r0, %[arg0]\n\t" // Set arg0-arg2
79 "mov r1, %[arg1]\n\t" // TODO: Any way to use constraints like on x86?
80 "mov r2, %[arg2]\n\t"
81 // Use r9 last as we don't know whether it was used for arg0-arg2
82 "mov r9, #0\n\t" // Push nullptr to terminate stack
83 "push {r9}\n\t"
84 ".cfi_adjust_cfa_offset 4\n\t"
85 "mov r9, %[self]\n\t" // Set the thread
86 "blx %[code]\n\t" // Call the stub
Andreas Gampe00c1e6d2014-04-25 15:47:13 -070087 "add sp, sp, #12\n\t" // Pop nullptr and padding
88 ".cfi_adjust_cfa_offset -12\n\t"
89 "pop {r1-r12, lr}\n\t" // Restore state
90 ".cfi_adjust_cfa_offset -52\n\t"
Andreas Gampe525cde22014-04-22 15:44:50 -070091 "mov %[result], r0\n\t" // Save the result
92 : [result] "=r" (result)
93 // Use the result from r0
94 : [arg0] "0"(arg0), [arg1] "r"(arg1), [arg2] "r"(arg2), [code] "r"(code), [self] "r"(self)
95 : ); // clobber.
96#elif defined(__aarch64__)
97 __asm__ __volatile__(
98 "sub sp, sp, #48\n\t" // Reserve stack space, 16B aligned
Andreas Gampe00c1e6d2014-04-25 15:47:13 -070099 ".cfi_adjust_cfa_offset 48\n\t"
Andreas Gampe525cde22014-04-22 15:44:50 -0700100 "stp xzr, x1, [sp]\n\t" // nullptr(end of quick stack), x1
101 "stp x2, x18, [sp, #16]\n\t" // Save x2, x18(xSELF)
102 "str x30, [sp, #32]\n\t" // Save xLR
103 "mov x0, %[arg0]\n\t" // Set arg0-arg2
104 "mov x1, %[arg1]\n\t" // TODO: Any way to use constraints like on x86?
105 "mov x2, %[arg2]\n\t"
106 // Use r18 last as we don't know whether it was used for arg0-arg2
107 "mov x18, %[self]\n\t" // Set the thread
108 "blr %[code]\n\t" // Call the stub
109 "ldp x1, x2, [sp, #8]\n\t" // Restore x1, x2
110 "ldp x18, x30, [sp, #24]\n\t" // Restore xSELF, xLR
111 "add sp, sp, #48\n\t" // Free stack space
Andreas Gampe00c1e6d2014-04-25 15:47:13 -0700112 ".cfi_adjust_cfa_offset -48\n\t"
Andreas Gampe525cde22014-04-22 15:44:50 -0700113 "mov %[result], x0\n\t" // Save the result
114 : [result] "=r" (result)
115 // Use the result from r0
116 : [arg0] "0"(arg0), [arg1] "r"(arg1), [arg2] "r"(arg2), [code] "r"(code), [self] "r"(self)
117 : "x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15", "x16", "x17"); // clobber.
118#elif defined(__x86_64__)
119 // Note: Uses the native convention
120 // TODO: Set the thread?
121 __asm__ __volatile__(
122 "pushq $0\n\t" // Push nullptr to terminate quick stack
123 "pushq $0\n\t" // 16B alignment padding
Andreas Gampe00c1e6d2014-04-25 15:47:13 -0700124 ".cfi_adjust_cfa_offset 16\n\t"
Andreas Gampe525cde22014-04-22 15:44:50 -0700125 "call *%%rax\n\t" // Call the stub
Andreas Gampef4e910b2014-04-29 16:55:52 -0700126 "addq $16, %%rsp\n\t" // Pop nullptr and padding
127 ".cfi_adjust_cfa_offset -16\n\t"
Andreas Gampe525cde22014-04-22 15:44:50 -0700128 : "=a" (result)
129 // Use the result from rax
130 : "D"(arg0), "S"(arg1), "d"(arg2), "a"(code)
131 // This places arg0 into rdi, arg1 into rsi, arg2 into rdx, and code into rax
Andreas Gampef4e910b2014-04-29 16:55:52 -0700132 : "rbx", "rcx", "rbp", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"); // clobber all
Andreas Gampe525cde22014-04-22 15:44:50 -0700133 // TODO: Should we clobber the other registers?
Andreas Gampe525cde22014-04-22 15:44:50 -0700134#else
135 LOG(WARNING) << "Was asked to invoke for an architecture I do not understand.";
136 result = 0;
137#endif
138 // Pop transition.
139 self->PopManagedStackFragment(fragment);
140 return result;
141 }
142};
143
144
145#if defined(__i386__) || defined(__x86_64__)
146extern "C" void art_quick_memcpy(void);
147#endif
148
149TEST_F(StubTest, Memcpy) {
150#if defined(__i386__) || defined(__x86_64__)
151 Thread* self = Thread::Current();
152
153 uint32_t orig[20];
154 uint32_t trg[20];
155 for (size_t i = 0; i < 20; ++i) {
156 orig[i] = i;
157 trg[i] = 0;
158 }
159
160 Invoke3(reinterpret_cast<size_t>(&trg[4]), reinterpret_cast<size_t>(&orig[4]),
161 10 * sizeof(uint32_t), reinterpret_cast<uintptr_t>(&art_quick_memcpy), self);
162
163 EXPECT_EQ(orig[0], trg[0]);
164
165 for (size_t i = 1; i < 4; ++i) {
166 EXPECT_NE(orig[i], trg[i]);
167 }
168
169 for (size_t i = 4; i < 14; ++i) {
170 EXPECT_EQ(orig[i], trg[i]);
171 }
172
173 for (size_t i = 14; i < 20; ++i) {
174 EXPECT_NE(orig[i], trg[i]);
175 }
176
177 // TODO: Test overlapping?
178
179#else
180 LOG(INFO) << "Skipping memcpy as I don't know how to do that on " << kRuntimeISA;
181 // Force-print to std::cout so it's also outside the logcat.
182 std::cout << "Skipping memcpy as I don't know how to do that on " << kRuntimeISA << std::endl;
183#endif
184}
185
Alexei Zavjalov80c79342014-05-02 16:45:40 +0700186#if defined(__i386__) || defined(__arm__) || defined(__x86_64__)
Andreas Gampe525cde22014-04-22 15:44:50 -0700187extern "C" void art_quick_lock_object(void);
188#endif
189
190TEST_F(StubTest, LockObject) {
Alexei Zavjalov80c79342014-05-02 16:45:40 +0700191#if defined(__i386__) || defined(__arm__) || defined(__x86_64__)
Andreas Gampe2ba8d4b2014-05-02 17:33:17 -0700192 static constexpr size_t kThinLockLoops = 100;
193
Andreas Gampe525cde22014-04-22 15:44:50 -0700194 Thread* self = Thread::Current();
195 // Create an object
196 ScopedObjectAccess soa(self);
197 // garbage is created during ClassLinker::Init
198
199 SirtRef<mirror::String> obj(soa.Self(),
200 mirror::String::AllocFromModifiedUtf8(soa.Self(), "hello, world!"));
201 LockWord lock = obj->GetLockWord(false);
202 LockWord::LockState old_state = lock.GetState();
203 EXPECT_EQ(LockWord::LockState::kUnlocked, old_state);
204
205 Invoke3(reinterpret_cast<size_t>(obj.get()), 0U, 0U,
206 reinterpret_cast<uintptr_t>(&art_quick_lock_object), self);
207
208 LockWord lock_after = obj->GetLockWord(false);
209 LockWord::LockState new_state = lock_after.GetState();
210 EXPECT_EQ(LockWord::LockState::kThinLocked, new_state);
Andreas Gampe7177d7c2014-05-02 12:10:02 -0700211 EXPECT_EQ(lock_after.ThinLockCount(), 0U); // Thin lock starts count at zero
212
213 for (size_t i = 1; i < kThinLockLoops; ++i) {
214 Invoke3(reinterpret_cast<size_t>(obj.get()), 0U, 0U,
215 reinterpret_cast<uintptr_t>(&art_quick_lock_object), self);
216
217 // Check we're at lock count i
218
219 LockWord l_inc = obj->GetLockWord(false);
220 LockWord::LockState l_inc_state = l_inc.GetState();
221 EXPECT_EQ(LockWord::LockState::kThinLocked, l_inc_state);
222 EXPECT_EQ(l_inc.ThinLockCount(), i);
223 }
224
225 // TODO: Improve this test. Somehow force it to go to fat locked. But that needs another thread.
226
227#else
228 LOG(INFO) << "Skipping lock_object as I don't know how to do that on " << kRuntimeISA;
229 // Force-print to std::cout so it's also outside the logcat.
230 std::cout << "Skipping lock_object as I don't know how to do that on " << kRuntimeISA << std::endl;
231#endif
232}
233
234class RandGen {
235 public:
236 explicit RandGen(uint32_t seed) : val_(seed) {}
237
238 uint32_t next() {
239 val_ = val_ * 48271 % 2147483647 + 13;
240 return val_;
241 }
242
243 uint32_t val_;
244};
245
246
247#if defined(__i386__) || defined(__arm__) || defined(__x86_64__)
248extern "C" void art_quick_lock_object(void);
249extern "C" void art_quick_unlock_object(void);
250#endif
251
252TEST_F(StubTest, UnlockObject) {
253#if defined(__i386__) || defined(__arm__) || defined(__x86_64__)
Andreas Gampe2ba8d4b2014-05-02 17:33:17 -0700254 static constexpr size_t kThinLockLoops = 100;
255
Andreas Gampe7177d7c2014-05-02 12:10:02 -0700256 Thread* self = Thread::Current();
257 // Create an object
258 ScopedObjectAccess soa(self);
259 // garbage is created during ClassLinker::Init
260
261 SirtRef<mirror::String> obj(soa.Self(),
262 mirror::String::AllocFromModifiedUtf8(soa.Self(), "hello, world!"));
263 LockWord lock = obj->GetLockWord(false);
264 LockWord::LockState old_state = lock.GetState();
265 EXPECT_EQ(LockWord::LockState::kUnlocked, old_state);
266
267 Invoke3(reinterpret_cast<size_t>(obj.get()), 0U, 0U,
268 reinterpret_cast<uintptr_t>(&art_quick_unlock_object), self);
269
270 // This should be an illegal monitor state.
271 EXPECT_TRUE(self->IsExceptionPending());
272 self->ClearException();
273
274 LockWord lock_after = obj->GetLockWord(false);
275 LockWord::LockState new_state = lock_after.GetState();
276 EXPECT_EQ(LockWord::LockState::kUnlocked, new_state);
Andreas Gampe525cde22014-04-22 15:44:50 -0700277
278 Invoke3(reinterpret_cast<size_t>(obj.get()), 0U, 0U,
279 reinterpret_cast<uintptr_t>(&art_quick_lock_object), self);
280
281 LockWord lock_after2 = obj->GetLockWord(false);
282 LockWord::LockState new_state2 = lock_after2.GetState();
283 EXPECT_EQ(LockWord::LockState::kThinLocked, new_state2);
284
Andreas Gampe7177d7c2014-05-02 12:10:02 -0700285 Invoke3(reinterpret_cast<size_t>(obj.get()), 0U, 0U,
286 reinterpret_cast<uintptr_t>(&art_quick_unlock_object), self);
287
288 LockWord lock_after3 = obj->GetLockWord(false);
289 LockWord::LockState new_state3 = lock_after3.GetState();
290 EXPECT_EQ(LockWord::LockState::kUnlocked, new_state3);
291
292 // Stress test:
293 // Keep a number of objects and their locks in flight. Randomly lock or unlock one of them in
294 // each step.
295
296 RandGen r(0x1234);
297
298 constexpr size_t kNumberOfLocks = 10; // Number of objects = lock
299 constexpr size_t kIterations = 10000; // Number of iterations
300
301 size_t counts[kNumberOfLocks];
302 SirtRef<mirror::String>* objects[kNumberOfLocks];
303
304 // Initialize = allocate.
305 for (size_t i = 0; i < kNumberOfLocks; ++i) {
306 counts[i] = 0;
307 objects[i] = new SirtRef<mirror::String>(soa.Self(),
308 mirror::String::AllocFromModifiedUtf8(soa.Self(), ""));
309 }
310
311 for (size_t i = 0; i < kIterations; ++i) {
312 // Select which lock to update.
313 size_t index = r.next() % kNumberOfLocks;
314
315 bool lock; // Whether to lock or unlock in this step.
316 if (counts[index] == 0) {
317 lock = true;
318 } else if (counts[index] == kThinLockLoops) {
319 lock = false;
320 } else {
321 // Randomly.
322 lock = r.next() % 2 == 0;
323 }
324
325 if (lock) {
326 Invoke3(reinterpret_cast<size_t>(objects[index]->get()), 0U, 0U,
327 reinterpret_cast<uintptr_t>(&art_quick_lock_object), self);
328 counts[index]++;
329 } else {
330 Invoke3(reinterpret_cast<size_t>(objects[index]->get()), 0U, 0U,
331 reinterpret_cast<uintptr_t>(&art_quick_unlock_object), self);
332 counts[index]--;
333 }
334
335 EXPECT_FALSE(self->IsExceptionPending());
336
337 // Check the new state.
338 LockWord lock_iter = objects[index]->get()->GetLockWord(false);
339 LockWord::LockState iter_state = lock_iter.GetState();
340 if (counts[index] > 0) {
341 EXPECT_EQ(LockWord::LockState::kThinLocked, iter_state);
342 EXPECT_EQ(counts[index] - 1, lock_iter.ThinLockCount());
343 } else {
344 EXPECT_EQ(LockWord::LockState::kUnlocked, iter_state);
345 }
346 }
347
348 // Unlock the remaining count times and then check it's unlocked. Then deallocate.
349 // Go reverse order to correctly handle SirtRefs.
350 for (size_t i = 0; i < kNumberOfLocks; ++i) {
351 size_t index = kNumberOfLocks - 1 - i;
352 size_t count = counts[index];
353 while (count > 0) {
354 Invoke3(reinterpret_cast<size_t>(objects[index]->get()), 0U, 0U,
355 reinterpret_cast<uintptr_t>(&art_quick_unlock_object), self);
356
357 count--;
358 }
359
360 LockWord lock_after4 = objects[index]->get()->GetLockWord(false);
361 LockWord::LockState new_state4 = lock_after4.GetState();
362 EXPECT_EQ(LockWord::LockState::kUnlocked, new_state4);
363
364 delete objects[index];
365 }
366
Andreas Gampe525cde22014-04-22 15:44:50 -0700367 // TODO: Improve this test. Somehow force it to go to fat locked. But that needs another thread.
368
369#else
Andreas Gampe7177d7c2014-05-02 12:10:02 -0700370 LOG(INFO) << "Skipping unlock_object as I don't know how to do that on " << kRuntimeISA;
Andreas Gampe525cde22014-04-22 15:44:50 -0700371 // Force-print to std::cout so it's also outside the logcat.
Andreas Gampe7177d7c2014-05-02 12:10:02 -0700372 std::cout << "Skipping unlock_object as I don't know how to do that on " << kRuntimeISA << std::endl;
Andreas Gampe525cde22014-04-22 15:44:50 -0700373#endif
374}
375
376
377#if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || defined(__x86_64__)
378extern "C" void art_quick_check_cast(void);
379#endif
380
381TEST_F(StubTest, CheckCast) {
382#if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || defined(__x86_64__)
383 Thread* self = Thread::Current();
384 // Find some classes.
385 ScopedObjectAccess soa(self);
386 // garbage is created during ClassLinker::Init
387
388 SirtRef<mirror::Class> c(soa.Self(), class_linker_->FindSystemClass(soa.Self(),
389 "[Ljava/lang/Object;"));
390 SirtRef<mirror::Class> c2(soa.Self(), class_linker_->FindSystemClass(soa.Self(),
391 "[Ljava/lang/String;"));
392
393 EXPECT_FALSE(self->IsExceptionPending());
394
395 Invoke3(reinterpret_cast<size_t>(c.get()), reinterpret_cast<size_t>(c.get()), 0U,
396 reinterpret_cast<uintptr_t>(&art_quick_check_cast), self);
397
398 EXPECT_FALSE(self->IsExceptionPending());
399
400 Invoke3(reinterpret_cast<size_t>(c2.get()), reinterpret_cast<size_t>(c2.get()), 0U,
401 reinterpret_cast<uintptr_t>(&art_quick_check_cast), self);
402
403 EXPECT_FALSE(self->IsExceptionPending());
404
405 Invoke3(reinterpret_cast<size_t>(c.get()), reinterpret_cast<size_t>(c2.get()), 0U,
406 reinterpret_cast<uintptr_t>(&art_quick_check_cast), self);
407
408 EXPECT_FALSE(self->IsExceptionPending());
409
410 // TODO: Make the following work. But that would require correct managed frames.
411
412 Invoke3(reinterpret_cast<size_t>(c2.get()), reinterpret_cast<size_t>(c.get()), 0U,
413 reinterpret_cast<uintptr_t>(&art_quick_check_cast), self);
414
415 EXPECT_TRUE(self->IsExceptionPending());
416 self->ClearException();
417
418#else
419 LOG(INFO) << "Skipping check_cast as I don't know how to do that on " << kRuntimeISA;
420 // Force-print to std::cout so it's also outside the logcat.
421 std::cout << "Skipping check_cast as I don't know how to do that on " << kRuntimeISA << std::endl;
422#endif
423}
424
425
Andreas Gampef4e910b2014-04-29 16:55:52 -0700426#if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || defined(__x86_64__)
Andreas Gampe525cde22014-04-22 15:44:50 -0700427extern "C" void art_quick_aput_obj_with_null_and_bound_check(void);
428// Do not check non-checked ones, we'd need handlers and stuff...
429#endif
430
431TEST_F(StubTest, APutObj) {
Hiroshi Yamauchid6881ae2014-04-28 17:21:48 -0700432 TEST_DISABLED_FOR_HEAP_REFERENCE_POISONING();
433
Andreas Gampef4e910b2014-04-29 16:55:52 -0700434#if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || defined(__x86_64__)
Andreas Gampe525cde22014-04-22 15:44:50 -0700435 Thread* self = Thread::Current();
436 // Create an object
437 ScopedObjectAccess soa(self);
438 // garbage is created during ClassLinker::Init
439
440 SirtRef<mirror::Class> c(soa.Self(), class_linker_->FindSystemClass(soa.Self(),
441 "Ljava/lang/Object;"));
442 SirtRef<mirror::Class> c2(soa.Self(), class_linker_->FindSystemClass(soa.Self(),
443 "Ljava/lang/String;"));
444 SirtRef<mirror::Class> ca(soa.Self(), class_linker_->FindSystemClass(soa.Self(),
445 "[Ljava/lang/String;"));
446
447 // Build a string array of size 1
448 SirtRef<mirror::ObjectArray<mirror::Object> > array(soa.Self(),
Andreas Gampef4e910b2014-04-29 16:55:52 -0700449 mirror::ObjectArray<mirror::Object>::Alloc(soa.Self(), ca.get(), 10));
Andreas Gampe525cde22014-04-22 15:44:50 -0700450
451 // Build a string -> should be assignable
452 SirtRef<mirror::Object> str_obj(soa.Self(),
453 mirror::String::AllocFromModifiedUtf8(soa.Self(), "hello, world!"));
454
455 // Build a generic object -> should fail assigning
456 SirtRef<mirror::Object> obj_obj(soa.Self(), c->AllocObject(soa.Self()));
457
458 // Play with it...
459
460 // 1) Success cases
Andreas Gampef4e910b2014-04-29 16:55:52 -0700461 // 1.1) Assign str_obj to array[0..3]
Andreas Gampe525cde22014-04-22 15:44:50 -0700462
463 EXPECT_FALSE(self->IsExceptionPending());
464
465 Invoke3(reinterpret_cast<size_t>(array.get()), 0U, reinterpret_cast<size_t>(str_obj.get()),
466 reinterpret_cast<uintptr_t>(&art_quick_aput_obj_with_null_and_bound_check), self);
467
468 EXPECT_FALSE(self->IsExceptionPending());
Andreas Gampef4e910b2014-04-29 16:55:52 -0700469 EXPECT_EQ(str_obj.get(), array->Get(0));
Andreas Gampe525cde22014-04-22 15:44:50 -0700470
Andreas Gampef4e910b2014-04-29 16:55:52 -0700471 Invoke3(reinterpret_cast<size_t>(array.get()), 1U, reinterpret_cast<size_t>(str_obj.get()),
472 reinterpret_cast<uintptr_t>(&art_quick_aput_obj_with_null_and_bound_check), self);
473
474 EXPECT_FALSE(self->IsExceptionPending());
475 EXPECT_EQ(str_obj.get(), array->Get(1));
476
477 Invoke3(reinterpret_cast<size_t>(array.get()), 2U, reinterpret_cast<size_t>(str_obj.get()),
478 reinterpret_cast<uintptr_t>(&art_quick_aput_obj_with_null_and_bound_check), self);
479
480 EXPECT_FALSE(self->IsExceptionPending());
481 EXPECT_EQ(str_obj.get(), array->Get(2));
482
483 Invoke3(reinterpret_cast<size_t>(array.get()), 3U, reinterpret_cast<size_t>(str_obj.get()),
484 reinterpret_cast<uintptr_t>(&art_quick_aput_obj_with_null_and_bound_check), self);
485
486 EXPECT_FALSE(self->IsExceptionPending());
487 EXPECT_EQ(str_obj.get(), array->Get(3));
488
489 // 1.2) Assign null to array[0..3]
Andreas Gampe525cde22014-04-22 15:44:50 -0700490
491 Invoke3(reinterpret_cast<size_t>(array.get()), 0U, reinterpret_cast<size_t>(nullptr),
492 reinterpret_cast<uintptr_t>(&art_quick_aput_obj_with_null_and_bound_check), self);
493
494 EXPECT_FALSE(self->IsExceptionPending());
Andreas Gampef4e910b2014-04-29 16:55:52 -0700495 EXPECT_EQ(nullptr, array->Get(0));
496
497 Invoke3(reinterpret_cast<size_t>(array.get()), 1U, reinterpret_cast<size_t>(nullptr),
498 reinterpret_cast<uintptr_t>(&art_quick_aput_obj_with_null_and_bound_check), self);
499
500 EXPECT_FALSE(self->IsExceptionPending());
501 EXPECT_EQ(nullptr, array->Get(1));
502
503 Invoke3(reinterpret_cast<size_t>(array.get()), 2U, reinterpret_cast<size_t>(nullptr),
504 reinterpret_cast<uintptr_t>(&art_quick_aput_obj_with_null_and_bound_check), self);
505
506 EXPECT_FALSE(self->IsExceptionPending());
507 EXPECT_EQ(nullptr, array->Get(2));
508
509 Invoke3(reinterpret_cast<size_t>(array.get()), 3U, reinterpret_cast<size_t>(nullptr),
510 reinterpret_cast<uintptr_t>(&art_quick_aput_obj_with_null_and_bound_check), self);
511
512 EXPECT_FALSE(self->IsExceptionPending());
513 EXPECT_EQ(nullptr, array->Get(3));
Andreas Gampe525cde22014-04-22 15:44:50 -0700514
515 // TODO: Check _which_ exception is thrown. Then make 3) check that it's the right check order.
516
517 // 2) Failure cases (str into str[])
518 // 2.1) Array = null
519 // TODO: Throwing NPE needs actual DEX code
520
521// Invoke3(reinterpret_cast<size_t>(nullptr), 0U, reinterpret_cast<size_t>(str_obj.get()),
522// reinterpret_cast<uintptr_t>(&art_quick_aput_obj_with_null_and_bound_check), self);
523//
524// EXPECT_TRUE(self->IsExceptionPending());
525// self->ClearException();
526
527 // 2.2) Index < 0
528
529 Invoke3(reinterpret_cast<size_t>(array.get()), static_cast<size_t>(-1),
530 reinterpret_cast<size_t>(str_obj.get()),
531 reinterpret_cast<uintptr_t>(&art_quick_aput_obj_with_null_and_bound_check), self);
532
533 EXPECT_TRUE(self->IsExceptionPending());
534 self->ClearException();
535
536 // 2.3) Index > 0
537
Andreas Gampef4e910b2014-04-29 16:55:52 -0700538 Invoke3(reinterpret_cast<size_t>(array.get()), 10U, reinterpret_cast<size_t>(str_obj.get()),
Andreas Gampe525cde22014-04-22 15:44:50 -0700539 reinterpret_cast<uintptr_t>(&art_quick_aput_obj_with_null_and_bound_check), self);
540
541 EXPECT_TRUE(self->IsExceptionPending());
542 self->ClearException();
543
544 // 3) Failure cases (obj into str[])
545
546 Invoke3(reinterpret_cast<size_t>(array.get()), 0U, reinterpret_cast<size_t>(obj_obj.get()),
547 reinterpret_cast<uintptr_t>(&art_quick_aput_obj_with_null_and_bound_check), self);
548
549 EXPECT_TRUE(self->IsExceptionPending());
550 self->ClearException();
551
552 // Tests done.
553#else
554 LOG(INFO) << "Skipping aput_obj as I don't know how to do that on " << kRuntimeISA;
555 // Force-print to std::cout so it's also outside the logcat.
556 std::cout << "Skipping aput_obj as I don't know how to do that on " << kRuntimeISA << std::endl;
557#endif
558}
559
Andreas Gampe00c1e6d2014-04-25 15:47:13 -0700560
561#if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || defined(__x86_64__)
562extern "C" void art_quick_alloc_object_rosalloc(void);
563extern "C" void art_quick_alloc_object_resolved_rosalloc(void);
564extern "C" void art_quick_alloc_object_initialized_rosalloc(void);
565#endif
566
567TEST_F(StubTest, AllocObject) {
568 TEST_DISABLED_FOR_HEAP_REFERENCE_POISONING();
569
570#if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || defined(__x86_64__)
571 // TODO: Check the "Unresolved" allocation stubs
572
573 Thread* self = Thread::Current();
574 // Create an object
575 ScopedObjectAccess soa(self);
576 // garbage is created during ClassLinker::Init
577
578 SirtRef<mirror::Class> c(soa.Self(), class_linker_->FindSystemClass(soa.Self(),
579 "Ljava/lang/Object;"));
580
581 // Play with it...
582
583 EXPECT_FALSE(self->IsExceptionPending());
584
585 {
586 // Use an arbitrary method from c to use as referrer
587 size_t result = Invoke3(static_cast<size_t>(c->GetDexTypeIndex()), // type_idx
588 reinterpret_cast<size_t>(c->GetVirtualMethod(0)), // arbitrary
589 0U,
590 reinterpret_cast<uintptr_t>(&art_quick_alloc_object_rosalloc),
591 self);
592
593 EXPECT_FALSE(self->IsExceptionPending());
594 EXPECT_NE(reinterpret_cast<size_t>(nullptr), result);
595 mirror::Object* obj = reinterpret_cast<mirror::Object*>(result);
596 EXPECT_EQ(c.get(), obj->GetClass());
597 VerifyObject(obj);
598 }
599
600 {
601 // We can use nullptr in the second argument as we do not need a method here (not used in
602 // resolved/initialized cases)
603 size_t result = Invoke3(reinterpret_cast<size_t>(c.get()), reinterpret_cast<size_t>(nullptr), 0U,
604 reinterpret_cast<uintptr_t>(&art_quick_alloc_object_resolved_rosalloc),
605 self);
606
607 EXPECT_FALSE(self->IsExceptionPending());
608 EXPECT_NE(reinterpret_cast<size_t>(nullptr), result);
609 mirror::Object* obj = reinterpret_cast<mirror::Object*>(result);
610 EXPECT_EQ(c.get(), obj->GetClass());
611 VerifyObject(obj);
612 }
613
614 {
615 // We can use nullptr in the second argument as we do not need a method here (not used in
616 // resolved/initialized cases)
617 size_t result = Invoke3(reinterpret_cast<size_t>(c.get()), reinterpret_cast<size_t>(nullptr), 0U,
618 reinterpret_cast<uintptr_t>(&art_quick_alloc_object_initialized_rosalloc),
619 self);
620
621 EXPECT_FALSE(self->IsExceptionPending());
622 EXPECT_NE(reinterpret_cast<size_t>(nullptr), result);
623 mirror::Object* obj = reinterpret_cast<mirror::Object*>(result);
624 EXPECT_EQ(c.get(), obj->GetClass());
625 VerifyObject(obj);
626 }
627
628 // Failure tests.
629
630 // Out-of-memory.
631 {
632 Runtime::Current()->GetHeap()->SetIdealFootprint(1 * GB);
633
634 // Array helps to fill memory faster.
635 SirtRef<mirror::Class> ca(soa.Self(), class_linker_->FindSystemClass(soa.Self(),
636 "[Ljava/lang/Object;"));
637 std::vector<SirtRef<mirror::Object>*> sirt_refs;
638 // Start allocating with 128K
639 size_t length = 128 * KB / 4;
640 while (length > 10) {
641 SirtRef<mirror::Object>* ref = new SirtRef<mirror::Object>(soa.Self(),
642 mirror::ObjectArray<mirror::Object>::Alloc(soa.Self(),
643 ca.get(),
644 length/4));
645 if (self->IsExceptionPending() || ref->get() == nullptr) {
646 self->ClearException();
647 delete ref;
648
649 // Try a smaller length
650 length = length / 8;
651 // Use at most half the reported free space.
652 size_t mem = Runtime::Current()->GetHeap()->GetFreeMemory();
653 if (length * 8 > mem) {
654 length = mem / 8;
655 }
656 } else {
657 sirt_refs.push_back(ref);
658 }
659 }
660 LOG(DEBUG) << "Used " << sirt_refs.size() << " arrays to fill space.";
661
662 // Allocate simple objects till it fails.
663 while (!self->IsExceptionPending()) {
664 SirtRef<mirror::Object>* ref = new SirtRef<mirror::Object>(soa.Self(),
665 c->AllocObject(soa.Self()));
666 if (!self->IsExceptionPending() && ref->get() != nullptr) {
667 sirt_refs.push_back(ref);
668 } else {
669 delete ref;
670 }
671 }
672 self->ClearException();
673
674 size_t result = Invoke3(reinterpret_cast<size_t>(c.get()), reinterpret_cast<size_t>(nullptr), 0U,
675 reinterpret_cast<uintptr_t>(&art_quick_alloc_object_initialized_rosalloc),
676 self);
677
678 EXPECT_TRUE(self->IsExceptionPending());
679 self->ClearException();
680 EXPECT_EQ(reinterpret_cast<size_t>(nullptr), result);
681
682 // Release all the allocated objects.
683 // Need to go backward to release SirtRef in the right order.
684 auto it = sirt_refs.rbegin();
685 auto end = sirt_refs.rend();
686 for (; it != end; ++it) {
687 delete *it;
688 }
689 }
690
691 // Tests done.
692#else
693 LOG(INFO) << "Skipping alloc_object as I don't know how to do that on " << kRuntimeISA;
694 // Force-print to std::cout so it's also outside the logcat.
695 std::cout << "Skipping alloc_object as I don't know how to do that on " << kRuntimeISA << std::endl;
696#endif
697}
698
699
700#if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || defined(__x86_64__)
701extern "C" void art_quick_alloc_array_rosalloc(void);
702extern "C" void art_quick_alloc_array_resolved_rosalloc(void);
703#endif
704
705TEST_F(StubTest, AllocObjectArray) {
706 TEST_DISABLED_FOR_HEAP_REFERENCE_POISONING();
707
708#if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || defined(__x86_64__)
709 // TODO: Check the "Unresolved" allocation stubs
710
711 Thread* self = Thread::Current();
712 // Create an object
713 ScopedObjectAccess soa(self);
714 // garbage is created during ClassLinker::Init
715
716 SirtRef<mirror::Class> c(soa.Self(), class_linker_->FindSystemClass(soa.Self(),
717 "[Ljava/lang/Object;"));
718
719 // Needed to have a linked method.
720 SirtRef<mirror::Class> c_obj(soa.Self(), class_linker_->FindSystemClass(soa.Self(),
721 "Ljava/lang/Object;"));
722
723 // Play with it...
724
725 EXPECT_FALSE(self->IsExceptionPending());
726/*
727 * For some reason this does not work, as the type_idx is artificial and outside what the
728 * resolved types of c_obj allow...
729 *
730 {
731 // Use an arbitrary method from c to use as referrer
732 size_t result = Invoke3(static_cast<size_t>(c->GetDexTypeIndex()), // type_idx
733 reinterpret_cast<size_t>(c_obj->GetVirtualMethod(0)), // arbitrary
734 10U,
735 reinterpret_cast<uintptr_t>(&art_quick_alloc_array_rosalloc),
736 self);
737
738 EXPECT_FALSE(self->IsExceptionPending());
739 EXPECT_NE(reinterpret_cast<size_t>(nullptr), result);
740 mirror::Array* obj = reinterpret_cast<mirror::Array*>(result);
741 EXPECT_EQ(c.get(), obj->GetClass());
742 VerifyObject(obj);
743 EXPECT_EQ(obj->GetLength(), 10);
744 }
745*/
746 {
747 // We can use nullptr in the second argument as we do not need a method here (not used in
748 // resolved/initialized cases)
749 size_t result = Invoke3(reinterpret_cast<size_t>(c.get()), reinterpret_cast<size_t>(nullptr), 10U,
750 reinterpret_cast<uintptr_t>(&art_quick_alloc_array_resolved_rosalloc),
751 self);
752
753 EXPECT_FALSE(self->IsExceptionPending());
754 EXPECT_NE(reinterpret_cast<size_t>(nullptr), result);
755 mirror::Object* obj = reinterpret_cast<mirror::Object*>(result);
756 EXPECT_TRUE(obj->IsArrayInstance());
757 EXPECT_TRUE(obj->IsObjectArray());
758 EXPECT_EQ(c.get(), obj->GetClass());
759 VerifyObject(obj);
760 mirror::Array* array = reinterpret_cast<mirror::Array*>(result);
761 EXPECT_EQ(array->GetLength(), 10);
762 }
763
764 // Failure tests.
765
766 // Out-of-memory.
767 {
768 size_t result = Invoke3(reinterpret_cast<size_t>(c.get()), reinterpret_cast<size_t>(nullptr),
769 GB, // that should fail...
770 reinterpret_cast<uintptr_t>(&art_quick_alloc_array_resolved_rosalloc),
771 self);
772
773 EXPECT_TRUE(self->IsExceptionPending());
774 self->ClearException();
775 EXPECT_EQ(reinterpret_cast<size_t>(nullptr), result);
776 }
777
778 // Tests done.
779#else
780 LOG(INFO) << "Skipping alloc_array as I don't know how to do that on " << kRuntimeISA;
781 // Force-print to std::cout so it's also outside the logcat.
782 std::cout << "Skipping alloc_array as I don't know how to do that on " << kRuntimeISA << std::endl;
783#endif
784}
785
Alexei Zavjalov315ccab2014-05-01 23:24:05 +0700786
Andreas Gampe266340d2014-05-02 07:55:24 -0700787#if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || defined(__x86_64__)
Alexei Zavjalov315ccab2014-05-01 23:24:05 +0700788extern "C" void art_quick_string_compareto(void);
789#endif
790
791TEST_F(StubTest, StringCompareTo) {
792 TEST_DISABLED_FOR_HEAP_REFERENCE_POISONING();
793
Andreas Gampe266340d2014-05-02 07:55:24 -0700794#if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || defined(__x86_64__)
Alexei Zavjalov315ccab2014-05-01 23:24:05 +0700795 // TODO: Check the "Unresolved" allocation stubs
796
797 Thread* self = Thread::Current();
798 ScopedObjectAccess soa(self);
799 // garbage is created during ClassLinker::Init
800
801 // Create some strings
802 // Use array so we can index into it and use a matrix for expected results
Andreas Gampe2ba8d4b2014-05-02 17:33:17 -0700803 // Setup: The first half is standard. The second half uses a non-zero offset.
804 // TODO: Shared backing arrays.
805 constexpr size_t base_string_count = 7;
806 const char* c[base_string_count] = { "", "", "a", "aa", "ab", "aac", "aac" , };
807
808 constexpr size_t string_count = 2 * base_string_count;
Alexei Zavjalov315ccab2014-05-01 23:24:05 +0700809
810 SirtRef<mirror::String>* s[string_count];
811
Andreas Gampe2ba8d4b2014-05-02 17:33:17 -0700812 for (size_t i = 0; i < base_string_count; ++i) {
Alexei Zavjalov315ccab2014-05-01 23:24:05 +0700813 s[i] = new SirtRef<mirror::String>(soa.Self(), mirror::String::AllocFromModifiedUtf8(soa.Self(),
814 c[i]));
815 }
816
Andreas Gampe2ba8d4b2014-05-02 17:33:17 -0700817 RandGen r(0x1234);
818
819 for (size_t i = base_string_count; i < string_count; ++i) {
820 s[i] = new SirtRef<mirror::String>(soa.Self(), mirror::String::AllocFromModifiedUtf8(soa.Self(),
821 c[i - base_string_count]));
822 int32_t length = s[i]->get()->GetLength();
823 if (length > 1) {
824 // Set a random offset and length.
825 int32_t new_offset = 1 + (r.next() % (length - 1));
826 int32_t rest = length - new_offset - 1;
827 int32_t new_length = 1 + (rest > 0 ? r.next() % rest : 0);
828
829 s[i]->get()->SetField32<false>(mirror::String::CountOffset(), new_length);
830 s[i]->get()->SetField32<false>(mirror::String::OffsetOffset(), new_offset);
831 }
832 }
833
Alexei Zavjalov315ccab2014-05-01 23:24:05 +0700834 // TODO: wide characters
835
836 // Matrix of expectations. First component is first parameter. Note we only check against the
Andreas Gampe2ba8d4b2014-05-02 17:33:17 -0700837 // sign, not the value. As we are testing random offsets, we need to compute this and need to
838 // rely on String::CompareTo being correct.
839 int32_t expected[string_count][string_count];
840 for (size_t x = 0; x < string_count; ++x) {
841 for (size_t y = 0; y < string_count; ++y) {
842 expected[x][y] = s[x]->get()->CompareTo(s[y]->get());
843 }
844 }
Alexei Zavjalov315ccab2014-05-01 23:24:05 +0700845
846 // Play with it...
847
848 for (size_t x = 0; x < string_count; ++x) {
849 for (size_t y = 0; y < string_count; ++y) {
850 // Test string_compareto x y
851 size_t result = Invoke3(reinterpret_cast<size_t>(s[x]->get()),
852 reinterpret_cast<size_t>(s[y]->get()), 0U,
853 reinterpret_cast<uintptr_t>(&art_quick_string_compareto), self);
854
855 EXPECT_FALSE(self->IsExceptionPending());
856
857 // The result is a 32b signed integer
858 union {
859 size_t r;
860 int32_t i;
861 } conv;
862 conv.r = result;
863 int32_t e = expected[x][y];
Andreas Gampe2ba8d4b2014-05-02 17:33:17 -0700864 EXPECT_TRUE(e == 0 ? conv.i == 0 : true) << "x=" << c[x] << " y=" << c[y] << " res=" <<
865 conv.r;
866 EXPECT_TRUE(e < 0 ? conv.i < 0 : true) << "x=" << c[x] << " y=" << c[y] << " res=" <<
867 conv.r;
868 EXPECT_TRUE(e > 0 ? conv.i > 0 : true) << "x=" << c[x] << " y=" << c[y] << " res=" <<
869 conv.r;
Alexei Zavjalov315ccab2014-05-01 23:24:05 +0700870 }
871 }
872
Andreas Gampe7177d7c2014-05-02 12:10:02 -0700873 // TODO: Deallocate things.
874
Alexei Zavjalov315ccab2014-05-01 23:24:05 +0700875 // Tests done.
876#else
877 LOG(INFO) << "Skipping string_compareto as I don't know how to do that on " << kRuntimeISA;
878 // Force-print to std::cout so it's also outside the logcat.
879 std::cout << "Skipping string_compareto as I don't know how to do that on " << kRuntimeISA <<
880 std::endl;
881#endif
882}
883
Andreas Gampe525cde22014-04-22 15:44:50 -0700884} // namespace art