blob: 7027b321eda8327809d89f22abea335e27f1df1f [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"
18
19#include <cstdio>
20
21namespace art {
22
23
24class StubTest : public CommonRuntimeTest {
25 protected:
26 // We need callee-save methods set up in the Runtime for exceptions.
27 void SetUp() OVERRIDE {
28 // Do the normal setup.
29 CommonRuntimeTest::SetUp();
30
31 {
32 // Create callee-save methods
33 ScopedObjectAccess soa(Thread::Current());
34 for (int i = 0; i < Runtime::kLastCalleeSaveType; i++) {
35 Runtime::CalleeSaveType type = Runtime::CalleeSaveType(i);
36 if (!runtime_->HasCalleeSaveMethod(type)) {
37 runtime_->SetCalleeSaveMethod(runtime_->CreateCalleeSaveMethod(kRuntimeISA, type), type);
38 }
39 }
40 }
41 }
42
Andreas Gampe00c1e6d2014-04-25 15:47:13 -070043 void SetUpRuntimeOptions(Runtime::Options *options) OVERRIDE {
44 // Use a smaller heap
45 for (std::pair<std::string, const void*>& pair : *options) {
46 if (pair.first.find("-Xmx") == 0) {
47 pair.first = "-Xmx4M"; // Smallest we can go.
48 }
49 }
50 }
Andreas Gampe525cde22014-04-22 15:44:50 -070051
52 size_t Invoke3(size_t arg0, size_t arg1, size_t arg2, uintptr_t code, Thread* self) {
53 // Push a transition back into managed code onto the linked list in thread.
54 ManagedStack fragment;
55 self->PushManagedStackFragment(&fragment);
56
57 size_t result;
58#if defined(__i386__)
59 // TODO: Set the thread?
60 __asm__ __volatile__(
61 "pushl $0\n\t" // Push nullptr to terminate quick stack
62 "call *%%edi\n\t" // Call the stub
63 "addl $4, %%esp" // Pop nullptr
64 : "=a" (result)
65 // Use the result from eax
66 : "a"(arg0), "c"(arg1), "d"(arg2), "D"(code)
67 // This places code into edi, arg0 into eax, arg1 into ecx, and arg2 into edx
68 : ); // clobber.
69 // TODO: Should we clobber the other registers? EBX gets clobbered by some of the stubs,
70 // but compilation fails when declaring that.
71#elif defined(__arm__)
72 __asm__ __volatile__(
Andreas Gampe00c1e6d2014-04-25 15:47:13 -070073 "push {r1-r12, lr}\n\t" // Save state, 13*4B = 52B
74 ".cfi_adjust_cfa_offset 52\n\t"
75 "sub sp, sp, #8\n\t" // +8B, so 16B aligned with nullptr
76 ".cfi_adjust_cfa_offset 8\n\t"
Andreas Gampe525cde22014-04-22 15:44:50 -070077 "mov r0, %[arg0]\n\t" // Set arg0-arg2
78 "mov r1, %[arg1]\n\t" // TODO: Any way to use constraints like on x86?
79 "mov r2, %[arg2]\n\t"
80 // Use r9 last as we don't know whether it was used for arg0-arg2
81 "mov r9, #0\n\t" // Push nullptr to terminate stack
82 "push {r9}\n\t"
83 ".cfi_adjust_cfa_offset 4\n\t"
84 "mov r9, %[self]\n\t" // Set the thread
85 "blx %[code]\n\t" // Call the stub
Andreas Gampe00c1e6d2014-04-25 15:47:13 -070086 "add sp, sp, #12\n\t" // Pop nullptr and padding
87 ".cfi_adjust_cfa_offset -12\n\t"
88 "pop {r1-r12, lr}\n\t" // Restore state
89 ".cfi_adjust_cfa_offset -52\n\t"
Andreas Gampe525cde22014-04-22 15:44:50 -070090 "mov %[result], r0\n\t" // Save the result
91 : [result] "=r" (result)
92 // Use the result from r0
93 : [arg0] "0"(arg0), [arg1] "r"(arg1), [arg2] "r"(arg2), [code] "r"(code), [self] "r"(self)
94 : ); // clobber.
95#elif defined(__aarch64__)
96 __asm__ __volatile__(
97 "sub sp, sp, #48\n\t" // Reserve stack space, 16B aligned
Andreas Gampe00c1e6d2014-04-25 15:47:13 -070098 ".cfi_adjust_cfa_offset 48\n\t"
Andreas Gampe525cde22014-04-22 15:44:50 -070099 "stp xzr, x1, [sp]\n\t" // nullptr(end of quick stack), x1
100 "stp x2, x18, [sp, #16]\n\t" // Save x2, x18(xSELF)
101 "str x30, [sp, #32]\n\t" // Save xLR
102 "mov x0, %[arg0]\n\t" // Set arg0-arg2
103 "mov x1, %[arg1]\n\t" // TODO: Any way to use constraints like on x86?
104 "mov x2, %[arg2]\n\t"
105 // Use r18 last as we don't know whether it was used for arg0-arg2
106 "mov x18, %[self]\n\t" // Set the thread
107 "blr %[code]\n\t" // Call the stub
108 "ldp x1, x2, [sp, #8]\n\t" // Restore x1, x2
109 "ldp x18, x30, [sp, #24]\n\t" // Restore xSELF, xLR
110 "add sp, sp, #48\n\t" // Free stack space
Andreas Gampe00c1e6d2014-04-25 15:47:13 -0700111 ".cfi_adjust_cfa_offset -48\n\t"
Andreas Gampe525cde22014-04-22 15:44:50 -0700112 "mov %[result], x0\n\t" // Save the result
113 : [result] "=r" (result)
114 // Use the result from r0
115 : [arg0] "0"(arg0), [arg1] "r"(arg1), [arg2] "r"(arg2), [code] "r"(code), [self] "r"(self)
116 : "x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15", "x16", "x17"); // clobber.
117#elif defined(__x86_64__)
118 // Note: Uses the native convention
119 // TODO: Set the thread?
120 __asm__ __volatile__(
121 "pushq $0\n\t" // Push nullptr to terminate quick stack
122 "pushq $0\n\t" // 16B alignment padding
Andreas Gampe00c1e6d2014-04-25 15:47:13 -0700123 ".cfi_adjust_cfa_offset 16\n\t"
Andreas Gampe525cde22014-04-22 15:44:50 -0700124 "call *%%rax\n\t" // Call the stub
Andreas Gampef4e910b2014-04-29 16:55:52 -0700125 "addq $16, %%rsp\n\t" // Pop nullptr and padding
126 ".cfi_adjust_cfa_offset -16\n\t"
Andreas Gampe525cde22014-04-22 15:44:50 -0700127 : "=a" (result)
128 // Use the result from rax
129 : "D"(arg0), "S"(arg1), "d"(arg2), "a"(code)
130 // This places arg0 into rdi, arg1 into rsi, arg2 into rdx, and code into rax
Andreas Gampef4e910b2014-04-29 16:55:52 -0700131 : "rbx", "rcx", "rbp", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"); // clobber all
Andreas Gampe525cde22014-04-22 15:44:50 -0700132 // TODO: Should we clobber the other registers?
Andreas Gampe525cde22014-04-22 15:44:50 -0700133#else
134 LOG(WARNING) << "Was asked to invoke for an architecture I do not understand.";
135 result = 0;
136#endif
137 // Pop transition.
138 self->PopManagedStackFragment(fragment);
139 return result;
140 }
141};
142
143
144#if defined(__i386__) || defined(__x86_64__)
145extern "C" void art_quick_memcpy(void);
146#endif
147
148TEST_F(StubTest, Memcpy) {
149#if defined(__i386__) || defined(__x86_64__)
150 Thread* self = Thread::Current();
151
152 uint32_t orig[20];
153 uint32_t trg[20];
154 for (size_t i = 0; i < 20; ++i) {
155 orig[i] = i;
156 trg[i] = 0;
157 }
158
159 Invoke3(reinterpret_cast<size_t>(&trg[4]), reinterpret_cast<size_t>(&orig[4]),
160 10 * sizeof(uint32_t), reinterpret_cast<uintptr_t>(&art_quick_memcpy), self);
161
162 EXPECT_EQ(orig[0], trg[0]);
163
164 for (size_t i = 1; i < 4; ++i) {
165 EXPECT_NE(orig[i], trg[i]);
166 }
167
168 for (size_t i = 4; i < 14; ++i) {
169 EXPECT_EQ(orig[i], trg[i]);
170 }
171
172 for (size_t i = 14; i < 20; ++i) {
173 EXPECT_NE(orig[i], trg[i]);
174 }
175
176 // TODO: Test overlapping?
177
178#else
179 LOG(INFO) << "Skipping memcpy as I don't know how to do that on " << kRuntimeISA;
180 // Force-print to std::cout so it's also outside the logcat.
181 std::cout << "Skipping memcpy as I don't know how to do that on " << kRuntimeISA << std::endl;
182#endif
183}
184
185
186#if defined(__i386__) || defined(__arm__)
187extern "C" void art_quick_lock_object(void);
188#endif
189
190TEST_F(StubTest, LockObject) {
191#if defined(__i386__) || defined(__arm__)
192 Thread* self = Thread::Current();
193 // Create an object
194 ScopedObjectAccess soa(self);
195 // garbage is created during ClassLinker::Init
196
197 SirtRef<mirror::String> obj(soa.Self(),
198 mirror::String::AllocFromModifiedUtf8(soa.Self(), "hello, world!"));
199 LockWord lock = obj->GetLockWord(false);
200 LockWord::LockState old_state = lock.GetState();
201 EXPECT_EQ(LockWord::LockState::kUnlocked, old_state);
202
203 Invoke3(reinterpret_cast<size_t>(obj.get()), 0U, 0U,
204 reinterpret_cast<uintptr_t>(&art_quick_lock_object), self);
205
206 LockWord lock_after = obj->GetLockWord(false);
207 LockWord::LockState new_state = lock_after.GetState();
208 EXPECT_EQ(LockWord::LockState::kThinLocked, new_state);
209
210 Invoke3(reinterpret_cast<size_t>(obj.get()), 0U, 0U,
211 reinterpret_cast<uintptr_t>(&art_quick_lock_object), self);
212
213 LockWord lock_after2 = obj->GetLockWord(false);
214 LockWord::LockState new_state2 = lock_after2.GetState();
215 EXPECT_EQ(LockWord::LockState::kThinLocked, new_state2);
216
217 // TODO: Improve this test. Somehow force it to go to fat locked. But that needs another thread.
218
219#else
220 LOG(INFO) << "Skipping lock_object as I don't know how to do that on " << kRuntimeISA;
221 // Force-print to std::cout so it's also outside the logcat.
222 std::cout << "Skipping lock_object as I don't know how to do that on " << kRuntimeISA << std::endl;
223#endif
224}
225
226
227#if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || defined(__x86_64__)
228extern "C" void art_quick_check_cast(void);
229#endif
230
231TEST_F(StubTest, CheckCast) {
232#if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || defined(__x86_64__)
233 Thread* self = Thread::Current();
234 // Find some classes.
235 ScopedObjectAccess soa(self);
236 // garbage is created during ClassLinker::Init
237
238 SirtRef<mirror::Class> c(soa.Self(), class_linker_->FindSystemClass(soa.Self(),
239 "[Ljava/lang/Object;"));
240 SirtRef<mirror::Class> c2(soa.Self(), class_linker_->FindSystemClass(soa.Self(),
241 "[Ljava/lang/String;"));
242
243 EXPECT_FALSE(self->IsExceptionPending());
244
245 Invoke3(reinterpret_cast<size_t>(c.get()), reinterpret_cast<size_t>(c.get()), 0U,
246 reinterpret_cast<uintptr_t>(&art_quick_check_cast), self);
247
248 EXPECT_FALSE(self->IsExceptionPending());
249
250 Invoke3(reinterpret_cast<size_t>(c2.get()), reinterpret_cast<size_t>(c2.get()), 0U,
251 reinterpret_cast<uintptr_t>(&art_quick_check_cast), self);
252
253 EXPECT_FALSE(self->IsExceptionPending());
254
255 Invoke3(reinterpret_cast<size_t>(c.get()), reinterpret_cast<size_t>(c2.get()), 0U,
256 reinterpret_cast<uintptr_t>(&art_quick_check_cast), self);
257
258 EXPECT_FALSE(self->IsExceptionPending());
259
260 // TODO: Make the following work. But that would require correct managed frames.
261
262 Invoke3(reinterpret_cast<size_t>(c2.get()), reinterpret_cast<size_t>(c.get()), 0U,
263 reinterpret_cast<uintptr_t>(&art_quick_check_cast), self);
264
265 EXPECT_TRUE(self->IsExceptionPending());
266 self->ClearException();
267
268#else
269 LOG(INFO) << "Skipping check_cast as I don't know how to do that on " << kRuntimeISA;
270 // Force-print to std::cout so it's also outside the logcat.
271 std::cout << "Skipping check_cast as I don't know how to do that on " << kRuntimeISA << std::endl;
272#endif
273}
274
275
Andreas Gampef4e910b2014-04-29 16:55:52 -0700276#if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || defined(__x86_64__)
Andreas Gampe525cde22014-04-22 15:44:50 -0700277extern "C" void art_quick_aput_obj_with_null_and_bound_check(void);
278// Do not check non-checked ones, we'd need handlers and stuff...
279#endif
280
281TEST_F(StubTest, APutObj) {
Hiroshi Yamauchid6881ae2014-04-28 17:21:48 -0700282 TEST_DISABLED_FOR_HEAP_REFERENCE_POISONING();
283
Andreas Gampef4e910b2014-04-29 16:55:52 -0700284#if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || defined(__x86_64__)
Andreas Gampe525cde22014-04-22 15:44:50 -0700285 Thread* self = Thread::Current();
286 // Create an object
287 ScopedObjectAccess soa(self);
288 // garbage is created during ClassLinker::Init
289
290 SirtRef<mirror::Class> c(soa.Self(), class_linker_->FindSystemClass(soa.Self(),
291 "Ljava/lang/Object;"));
292 SirtRef<mirror::Class> c2(soa.Self(), class_linker_->FindSystemClass(soa.Self(),
293 "Ljava/lang/String;"));
294 SirtRef<mirror::Class> ca(soa.Self(), class_linker_->FindSystemClass(soa.Self(),
295 "[Ljava/lang/String;"));
296
297 // Build a string array of size 1
298 SirtRef<mirror::ObjectArray<mirror::Object> > array(soa.Self(),
Andreas Gampef4e910b2014-04-29 16:55:52 -0700299 mirror::ObjectArray<mirror::Object>::Alloc(soa.Self(), ca.get(), 10));
Andreas Gampe525cde22014-04-22 15:44:50 -0700300
301 // Build a string -> should be assignable
302 SirtRef<mirror::Object> str_obj(soa.Self(),
303 mirror::String::AllocFromModifiedUtf8(soa.Self(), "hello, world!"));
304
305 // Build a generic object -> should fail assigning
306 SirtRef<mirror::Object> obj_obj(soa.Self(), c->AllocObject(soa.Self()));
307
308 // Play with it...
309
310 // 1) Success cases
Andreas Gampef4e910b2014-04-29 16:55:52 -0700311 // 1.1) Assign str_obj to array[0..3]
Andreas Gampe525cde22014-04-22 15:44:50 -0700312
313 EXPECT_FALSE(self->IsExceptionPending());
314
315 Invoke3(reinterpret_cast<size_t>(array.get()), 0U, reinterpret_cast<size_t>(str_obj.get()),
316 reinterpret_cast<uintptr_t>(&art_quick_aput_obj_with_null_and_bound_check), self);
317
318 EXPECT_FALSE(self->IsExceptionPending());
Andreas Gampef4e910b2014-04-29 16:55:52 -0700319 EXPECT_EQ(str_obj.get(), array->Get(0));
Andreas Gampe525cde22014-04-22 15:44:50 -0700320
Andreas Gampef4e910b2014-04-29 16:55:52 -0700321 Invoke3(reinterpret_cast<size_t>(array.get()), 1U, reinterpret_cast<size_t>(str_obj.get()),
322 reinterpret_cast<uintptr_t>(&art_quick_aput_obj_with_null_and_bound_check), self);
323
324 EXPECT_FALSE(self->IsExceptionPending());
325 EXPECT_EQ(str_obj.get(), array->Get(1));
326
327 Invoke3(reinterpret_cast<size_t>(array.get()), 2U, reinterpret_cast<size_t>(str_obj.get()),
328 reinterpret_cast<uintptr_t>(&art_quick_aput_obj_with_null_and_bound_check), self);
329
330 EXPECT_FALSE(self->IsExceptionPending());
331 EXPECT_EQ(str_obj.get(), array->Get(2));
332
333 Invoke3(reinterpret_cast<size_t>(array.get()), 3U, reinterpret_cast<size_t>(str_obj.get()),
334 reinterpret_cast<uintptr_t>(&art_quick_aput_obj_with_null_and_bound_check), self);
335
336 EXPECT_FALSE(self->IsExceptionPending());
337 EXPECT_EQ(str_obj.get(), array->Get(3));
338
339 // 1.2) Assign null to array[0..3]
Andreas Gampe525cde22014-04-22 15:44:50 -0700340
341 Invoke3(reinterpret_cast<size_t>(array.get()), 0U, reinterpret_cast<size_t>(nullptr),
342 reinterpret_cast<uintptr_t>(&art_quick_aput_obj_with_null_and_bound_check), self);
343
344 EXPECT_FALSE(self->IsExceptionPending());
Andreas Gampef4e910b2014-04-29 16:55:52 -0700345 EXPECT_EQ(nullptr, array->Get(0));
346
347 Invoke3(reinterpret_cast<size_t>(array.get()), 1U, reinterpret_cast<size_t>(nullptr),
348 reinterpret_cast<uintptr_t>(&art_quick_aput_obj_with_null_and_bound_check), self);
349
350 EXPECT_FALSE(self->IsExceptionPending());
351 EXPECT_EQ(nullptr, array->Get(1));
352
353 Invoke3(reinterpret_cast<size_t>(array.get()), 2U, reinterpret_cast<size_t>(nullptr),
354 reinterpret_cast<uintptr_t>(&art_quick_aput_obj_with_null_and_bound_check), self);
355
356 EXPECT_FALSE(self->IsExceptionPending());
357 EXPECT_EQ(nullptr, array->Get(2));
358
359 Invoke3(reinterpret_cast<size_t>(array.get()), 3U, reinterpret_cast<size_t>(nullptr),
360 reinterpret_cast<uintptr_t>(&art_quick_aput_obj_with_null_and_bound_check), self);
361
362 EXPECT_FALSE(self->IsExceptionPending());
363 EXPECT_EQ(nullptr, array->Get(3));
Andreas Gampe525cde22014-04-22 15:44:50 -0700364
365 // TODO: Check _which_ exception is thrown. Then make 3) check that it's the right check order.
366
367 // 2) Failure cases (str into str[])
368 // 2.1) Array = null
369 // TODO: Throwing NPE needs actual DEX code
370
371// Invoke3(reinterpret_cast<size_t>(nullptr), 0U, reinterpret_cast<size_t>(str_obj.get()),
372// reinterpret_cast<uintptr_t>(&art_quick_aput_obj_with_null_and_bound_check), self);
373//
374// EXPECT_TRUE(self->IsExceptionPending());
375// self->ClearException();
376
377 // 2.2) Index < 0
378
379 Invoke3(reinterpret_cast<size_t>(array.get()), static_cast<size_t>(-1),
380 reinterpret_cast<size_t>(str_obj.get()),
381 reinterpret_cast<uintptr_t>(&art_quick_aput_obj_with_null_and_bound_check), self);
382
383 EXPECT_TRUE(self->IsExceptionPending());
384 self->ClearException();
385
386 // 2.3) Index > 0
387
Andreas Gampef4e910b2014-04-29 16:55:52 -0700388 Invoke3(reinterpret_cast<size_t>(array.get()), 10U, reinterpret_cast<size_t>(str_obj.get()),
Andreas Gampe525cde22014-04-22 15:44:50 -0700389 reinterpret_cast<uintptr_t>(&art_quick_aput_obj_with_null_and_bound_check), self);
390
391 EXPECT_TRUE(self->IsExceptionPending());
392 self->ClearException();
393
394 // 3) Failure cases (obj into str[])
395
396 Invoke3(reinterpret_cast<size_t>(array.get()), 0U, reinterpret_cast<size_t>(obj_obj.get()),
397 reinterpret_cast<uintptr_t>(&art_quick_aput_obj_with_null_and_bound_check), self);
398
399 EXPECT_TRUE(self->IsExceptionPending());
400 self->ClearException();
401
402 // Tests done.
403#else
404 LOG(INFO) << "Skipping aput_obj as I don't know how to do that on " << kRuntimeISA;
405 // Force-print to std::cout so it's also outside the logcat.
406 std::cout << "Skipping aput_obj as I don't know how to do that on " << kRuntimeISA << std::endl;
407#endif
408}
409
Andreas Gampe00c1e6d2014-04-25 15:47:13 -0700410
411#if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || defined(__x86_64__)
412extern "C" void art_quick_alloc_object_rosalloc(void);
413extern "C" void art_quick_alloc_object_resolved_rosalloc(void);
414extern "C" void art_quick_alloc_object_initialized_rosalloc(void);
415#endif
416
417TEST_F(StubTest, AllocObject) {
418 TEST_DISABLED_FOR_HEAP_REFERENCE_POISONING();
419
420#if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || defined(__x86_64__)
421 // TODO: Check the "Unresolved" allocation stubs
422
423 Thread* self = Thread::Current();
424 // Create an object
425 ScopedObjectAccess soa(self);
426 // garbage is created during ClassLinker::Init
427
428 SirtRef<mirror::Class> c(soa.Self(), class_linker_->FindSystemClass(soa.Self(),
429 "Ljava/lang/Object;"));
430
431 // Play with it...
432
433 EXPECT_FALSE(self->IsExceptionPending());
434
435 {
436 // Use an arbitrary method from c to use as referrer
437 size_t result = Invoke3(static_cast<size_t>(c->GetDexTypeIndex()), // type_idx
438 reinterpret_cast<size_t>(c->GetVirtualMethod(0)), // arbitrary
439 0U,
440 reinterpret_cast<uintptr_t>(&art_quick_alloc_object_rosalloc),
441 self);
442
443 EXPECT_FALSE(self->IsExceptionPending());
444 EXPECT_NE(reinterpret_cast<size_t>(nullptr), result);
445 mirror::Object* obj = reinterpret_cast<mirror::Object*>(result);
446 EXPECT_EQ(c.get(), obj->GetClass());
447 VerifyObject(obj);
448 }
449
450 {
451 // We can use nullptr in the second argument as we do not need a method here (not used in
452 // resolved/initialized cases)
453 size_t result = Invoke3(reinterpret_cast<size_t>(c.get()), reinterpret_cast<size_t>(nullptr), 0U,
454 reinterpret_cast<uintptr_t>(&art_quick_alloc_object_resolved_rosalloc),
455 self);
456
457 EXPECT_FALSE(self->IsExceptionPending());
458 EXPECT_NE(reinterpret_cast<size_t>(nullptr), result);
459 mirror::Object* obj = reinterpret_cast<mirror::Object*>(result);
460 EXPECT_EQ(c.get(), obj->GetClass());
461 VerifyObject(obj);
462 }
463
464 {
465 // We can use nullptr in the second argument as we do not need a method here (not used in
466 // resolved/initialized cases)
467 size_t result = Invoke3(reinterpret_cast<size_t>(c.get()), reinterpret_cast<size_t>(nullptr), 0U,
468 reinterpret_cast<uintptr_t>(&art_quick_alloc_object_initialized_rosalloc),
469 self);
470
471 EXPECT_FALSE(self->IsExceptionPending());
472 EXPECT_NE(reinterpret_cast<size_t>(nullptr), result);
473 mirror::Object* obj = reinterpret_cast<mirror::Object*>(result);
474 EXPECT_EQ(c.get(), obj->GetClass());
475 VerifyObject(obj);
476 }
477
478 // Failure tests.
479
480 // Out-of-memory.
481 {
482 Runtime::Current()->GetHeap()->SetIdealFootprint(1 * GB);
483
484 // Array helps to fill memory faster.
485 SirtRef<mirror::Class> ca(soa.Self(), class_linker_->FindSystemClass(soa.Self(),
486 "[Ljava/lang/Object;"));
487 std::vector<SirtRef<mirror::Object>*> sirt_refs;
488 // Start allocating with 128K
489 size_t length = 128 * KB / 4;
490 while (length > 10) {
491 SirtRef<mirror::Object>* ref = new SirtRef<mirror::Object>(soa.Self(),
492 mirror::ObjectArray<mirror::Object>::Alloc(soa.Self(),
493 ca.get(),
494 length/4));
495 if (self->IsExceptionPending() || ref->get() == nullptr) {
496 self->ClearException();
497 delete ref;
498
499 // Try a smaller length
500 length = length / 8;
501 // Use at most half the reported free space.
502 size_t mem = Runtime::Current()->GetHeap()->GetFreeMemory();
503 if (length * 8 > mem) {
504 length = mem / 8;
505 }
506 } else {
507 sirt_refs.push_back(ref);
508 }
509 }
510 LOG(DEBUG) << "Used " << sirt_refs.size() << " arrays to fill space.";
511
512 // Allocate simple objects till it fails.
513 while (!self->IsExceptionPending()) {
514 SirtRef<mirror::Object>* ref = new SirtRef<mirror::Object>(soa.Self(),
515 c->AllocObject(soa.Self()));
516 if (!self->IsExceptionPending() && ref->get() != nullptr) {
517 sirt_refs.push_back(ref);
518 } else {
519 delete ref;
520 }
521 }
522 self->ClearException();
523
524 size_t result = Invoke3(reinterpret_cast<size_t>(c.get()), reinterpret_cast<size_t>(nullptr), 0U,
525 reinterpret_cast<uintptr_t>(&art_quick_alloc_object_initialized_rosalloc),
526 self);
527
528 EXPECT_TRUE(self->IsExceptionPending());
529 self->ClearException();
530 EXPECT_EQ(reinterpret_cast<size_t>(nullptr), result);
531
532 // Release all the allocated objects.
533 // Need to go backward to release SirtRef in the right order.
534 auto it = sirt_refs.rbegin();
535 auto end = sirt_refs.rend();
536 for (; it != end; ++it) {
537 delete *it;
538 }
539 }
540
541 // Tests done.
542#else
543 LOG(INFO) << "Skipping alloc_object as I don't know how to do that on " << kRuntimeISA;
544 // Force-print to std::cout so it's also outside the logcat.
545 std::cout << "Skipping alloc_object as I don't know how to do that on " << kRuntimeISA << std::endl;
546#endif
547}
548
549
550#if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || defined(__x86_64__)
551extern "C" void art_quick_alloc_array_rosalloc(void);
552extern "C" void art_quick_alloc_array_resolved_rosalloc(void);
553#endif
554
555TEST_F(StubTest, AllocObjectArray) {
556 TEST_DISABLED_FOR_HEAP_REFERENCE_POISONING();
557
558#if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || defined(__x86_64__)
559 // TODO: Check the "Unresolved" allocation stubs
560
561 Thread* self = Thread::Current();
562 // Create an object
563 ScopedObjectAccess soa(self);
564 // garbage is created during ClassLinker::Init
565
566 SirtRef<mirror::Class> c(soa.Self(), class_linker_->FindSystemClass(soa.Self(),
567 "[Ljava/lang/Object;"));
568
569 // Needed to have a linked method.
570 SirtRef<mirror::Class> c_obj(soa.Self(), class_linker_->FindSystemClass(soa.Self(),
571 "Ljava/lang/Object;"));
572
573 // Play with it...
574
575 EXPECT_FALSE(self->IsExceptionPending());
576/*
577 * For some reason this does not work, as the type_idx is artificial and outside what the
578 * resolved types of c_obj allow...
579 *
580 {
581 // Use an arbitrary method from c to use as referrer
582 size_t result = Invoke3(static_cast<size_t>(c->GetDexTypeIndex()), // type_idx
583 reinterpret_cast<size_t>(c_obj->GetVirtualMethod(0)), // arbitrary
584 10U,
585 reinterpret_cast<uintptr_t>(&art_quick_alloc_array_rosalloc),
586 self);
587
588 EXPECT_FALSE(self->IsExceptionPending());
589 EXPECT_NE(reinterpret_cast<size_t>(nullptr), result);
590 mirror::Array* obj = reinterpret_cast<mirror::Array*>(result);
591 EXPECT_EQ(c.get(), obj->GetClass());
592 VerifyObject(obj);
593 EXPECT_EQ(obj->GetLength(), 10);
594 }
595*/
596 {
597 // We can use nullptr in the second argument as we do not need a method here (not used in
598 // resolved/initialized cases)
599 size_t result = Invoke3(reinterpret_cast<size_t>(c.get()), reinterpret_cast<size_t>(nullptr), 10U,
600 reinterpret_cast<uintptr_t>(&art_quick_alloc_array_resolved_rosalloc),
601 self);
602
603 EXPECT_FALSE(self->IsExceptionPending());
604 EXPECT_NE(reinterpret_cast<size_t>(nullptr), result);
605 mirror::Object* obj = reinterpret_cast<mirror::Object*>(result);
606 EXPECT_TRUE(obj->IsArrayInstance());
607 EXPECT_TRUE(obj->IsObjectArray());
608 EXPECT_EQ(c.get(), obj->GetClass());
609 VerifyObject(obj);
610 mirror::Array* array = reinterpret_cast<mirror::Array*>(result);
611 EXPECT_EQ(array->GetLength(), 10);
612 }
613
614 // Failure tests.
615
616 // Out-of-memory.
617 {
618 size_t result = Invoke3(reinterpret_cast<size_t>(c.get()), reinterpret_cast<size_t>(nullptr),
619 GB, // that should fail...
620 reinterpret_cast<uintptr_t>(&art_quick_alloc_array_resolved_rosalloc),
621 self);
622
623 EXPECT_TRUE(self->IsExceptionPending());
624 self->ClearException();
625 EXPECT_EQ(reinterpret_cast<size_t>(nullptr), result);
626 }
627
628 // Tests done.
629#else
630 LOG(INFO) << "Skipping alloc_array as I don't know how to do that on " << kRuntimeISA;
631 // Force-print to std::cout so it's also outside the logcat.
632 std::cout << "Skipping alloc_array as I don't know how to do that on " << kRuntimeISA << std::endl;
633#endif
634}
635
Andreas Gampe525cde22014-04-22 15:44:50 -0700636} // namespace art