blob: fb53b1d5ef44980268a1c7e5008013d7d0648def [file] [log] [blame]
Andreas Gampe799681b2015-05-15 19:24:12 -07001/*
2 * Copyright (C) 2015 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 "unstarted_runtime.h"
18
19#include "class_linker.h"
20#include "common_runtime_test.h"
Jeff Hao400ce002015-05-29 10:53:17 -070021#include "dex_instruction.h"
Andreas Gampe799681b2015-05-15 19:24:12 -070022#include "handle.h"
23#include "handle_scope-inl.h"
Jeff Hao400ce002015-05-29 10:53:17 -070024#include "interpreter/interpreter_common.h"
Andreas Gampe799681b2015-05-15 19:24:12 -070025#include "mirror/class_loader.h"
26#include "mirror/string-inl.h"
27#include "runtime.h"
28#include "scoped_thread_state_change.h"
29#include "thread.h"
30
31namespace art {
32namespace interpreter {
33
34class UnstartedRuntimeTest : public CommonRuntimeTest {
35 protected:
36 // Re-expose all UnstartedRuntime implementations so we don't need to declare a million
37 // test friends.
38
39 // Methods that intercept available libcore implementations.
40#define UNSTARTED_DIRECT(Name, SigIgnored) \
41 static void Unstarted ## Name(Thread* self, \
42 ShadowFrame* shadow_frame, \
43 JValue* result, \
44 size_t arg_offset) \
Mathieu Chartier90443472015-07-16 20:32:27 -070045 SHARED_REQUIRES(Locks::mutator_lock_) { \
Andreas Gampe799681b2015-05-15 19:24:12 -070046 interpreter::UnstartedRuntime::Unstarted ## Name(self, shadow_frame, result, arg_offset); \
47 }
48#include "unstarted_runtime_list.h"
49 UNSTARTED_RUNTIME_DIRECT_LIST(UNSTARTED_DIRECT)
50#undef UNSTARTED_RUNTIME_DIRECT_LIST
51#undef UNSTARTED_RUNTIME_JNI_LIST
52#undef UNSTARTED_DIRECT
53
54 // Methods that are native.
Mathieu Chartiere401d142015-04-22 13:56:20 -070055#define UNSTARTED_JNI(Name, SigIgnored) \
Andreas Gampe799681b2015-05-15 19:24:12 -070056 static void UnstartedJNI ## Name(Thread* self, \
Mathieu Chartiere401d142015-04-22 13:56:20 -070057 ArtMethod* method, \
Andreas Gampe799681b2015-05-15 19:24:12 -070058 mirror::Object* receiver, \
59 uint32_t* args, \
60 JValue* result) \
Mathieu Chartier90443472015-07-16 20:32:27 -070061 SHARED_REQUIRES(Locks::mutator_lock_) { \
Andreas Gampe799681b2015-05-15 19:24:12 -070062 interpreter::UnstartedRuntime::UnstartedJNI ## Name(self, method, receiver, args, result); \
63 }
64#include "unstarted_runtime_list.h"
65 UNSTARTED_RUNTIME_JNI_LIST(UNSTARTED_JNI)
66#undef UNSTARTED_RUNTIME_DIRECT_LIST
67#undef UNSTARTED_RUNTIME_JNI_LIST
68#undef UNSTARTED_JNI
Andreas Gampe85a098a2016-03-31 13:30:53 -070069
70 // Helpers for ArrayCopy.
71 //
72 // Note: as we have to use handles, we use StackHandleScope to transfer data. Hardcode a size
73 // of three everywhere. That is enough to test all cases.
74
75 static mirror::ObjectArray<mirror::Object>* CreateObjectArray(
76 Thread* self,
77 mirror::Class* component_type,
78 const StackHandleScope<3>& data)
79 SHARED_REQUIRES(Locks::mutator_lock_) {
80 Runtime* runtime = Runtime::Current();
81 mirror::Class* array_type = runtime->GetClassLinker()->FindArrayClass(self, &component_type);
82 CHECK(array_type != nullptr);
83 mirror::ObjectArray<mirror::Object>* result =
84 mirror::ObjectArray<mirror::Object>::Alloc(self, array_type, 3);
85 CHECK(result != nullptr);
86 for (size_t i = 0; i < 3; ++i) {
87 result->Set(static_cast<int32_t>(i), data.GetReference(i));
88 CHECK(!self->IsExceptionPending());
89 }
90 return result;
91 }
92
93 static void CheckObjectArray(mirror::ObjectArray<mirror::Object>* array,
94 const StackHandleScope<3>& data)
95 SHARED_REQUIRES(Locks::mutator_lock_) {
96 CHECK_EQ(array->GetLength(), 3);
97 CHECK_EQ(data.NumberOfReferences(), 3U);
98 for (size_t i = 0; i < 3; ++i) {
99 EXPECT_EQ(data.GetReference(i), array->Get(static_cast<int32_t>(i))) << i;
100 }
101 }
102
103 void RunArrayCopy(Thread* self,
104 ShadowFrame* tmp,
105 bool expect_exception,
106 mirror::ObjectArray<mirror::Object>* src,
107 int32_t src_pos,
108 mirror::ObjectArray<mirror::Object>* dst,
109 int32_t dst_pos,
110 int32_t length)
111 SHARED_REQUIRES(Locks::mutator_lock_) {
112 JValue result;
113 tmp->SetVRegReference(0, src);
114 tmp->SetVReg(1, src_pos);
115 tmp->SetVRegReference(2, dst);
116 tmp->SetVReg(3, dst_pos);
117 tmp->SetVReg(4, length);
118 UnstartedSystemArraycopy(self, tmp, &result, 0);
119 bool exception_pending = self->IsExceptionPending();
120 EXPECT_EQ(exception_pending, expect_exception);
121 if (exception_pending) {
122 self->ClearException();
123 }
124 }
125
126 void RunArrayCopy(Thread* self,
127 ShadowFrame* tmp,
128 bool expect_exception,
129 mirror::Class* src_component_class,
130 mirror::Class* dst_component_class,
131 const StackHandleScope<3>& src_data,
132 int32_t src_pos,
133 const StackHandleScope<3>& dst_data,
134 int32_t dst_pos,
135 int32_t length,
136 const StackHandleScope<3>& expected_result)
137 SHARED_REQUIRES(Locks::mutator_lock_) {
138 StackHandleScope<3> hs_misc(self);
139 Handle<mirror::Class> dst_component_handle(hs_misc.NewHandle(dst_component_class));
140
141 Handle<mirror::ObjectArray<mirror::Object>> src_handle(
142 hs_misc.NewHandle(CreateObjectArray(self, src_component_class, src_data)));
143
144 Handle<mirror::ObjectArray<mirror::Object>> dst_handle(
145 hs_misc.NewHandle(CreateObjectArray(self, dst_component_handle.Get(), dst_data)));
146
147 RunArrayCopy(self,
148 tmp,
149 expect_exception,
150 src_handle.Get(),
151 src_pos,
152 dst_handle.Get(),
153 dst_pos,
154 length);
155 CheckObjectArray(dst_handle.Get(), expected_result);
156 }
Andreas Gampe799681b2015-05-15 19:24:12 -0700157};
158
159TEST_F(UnstartedRuntimeTest, MemoryPeekByte) {
160 Thread* self = Thread::Current();
161
162 ScopedObjectAccess soa(self);
163 constexpr const uint8_t base_array[] = "abcdefghijklmnop";
164 constexpr int32_t kBaseLen = sizeof(base_array) / sizeof(uint8_t);
165 const uint8_t* base_ptr = base_array;
166
167 JValue result;
168 ShadowFrame* tmp = ShadowFrame::CreateDeoptimizedFrame(10, nullptr, nullptr, 0);
169
170 for (int32_t i = 0; i < kBaseLen; ++i) {
171 tmp->SetVRegLong(0, static_cast<int64_t>(reinterpret_cast<intptr_t>(base_ptr + i)));
172
173 UnstartedMemoryPeekByte(self, tmp, &result, 0);
174
175 EXPECT_EQ(result.GetB(), static_cast<int8_t>(base_array[i]));
176 }
177
178 ShadowFrame::DeleteDeoptimizedFrame(tmp);
179}
180
181TEST_F(UnstartedRuntimeTest, MemoryPeekShort) {
182 Thread* self = Thread::Current();
183
184 ScopedObjectAccess soa(self);
185 constexpr const uint8_t base_array[] = "abcdefghijklmnop";
186 constexpr int32_t kBaseLen = sizeof(base_array) / sizeof(uint8_t);
187 const uint8_t* base_ptr = base_array;
188
189 JValue result;
190 ShadowFrame* tmp = ShadowFrame::CreateDeoptimizedFrame(10, nullptr, nullptr, 0);
191
192 int32_t adjusted_length = kBaseLen - sizeof(int16_t);
193 for (int32_t i = 0; i < adjusted_length; ++i) {
194 tmp->SetVRegLong(0, static_cast<int64_t>(reinterpret_cast<intptr_t>(base_ptr + i)));
195
196 UnstartedMemoryPeekShort(self, tmp, &result, 0);
197
198 typedef int16_t unaligned_short __attribute__ ((aligned (1)));
199 const unaligned_short* short_ptr = reinterpret_cast<const unaligned_short*>(base_ptr + i);
200 EXPECT_EQ(result.GetS(), *short_ptr);
201 }
202
203 ShadowFrame::DeleteDeoptimizedFrame(tmp);
204}
205
206TEST_F(UnstartedRuntimeTest, MemoryPeekInt) {
207 Thread* self = Thread::Current();
208
209 ScopedObjectAccess soa(self);
210 constexpr const uint8_t base_array[] = "abcdefghijklmnop";
211 constexpr int32_t kBaseLen = sizeof(base_array) / sizeof(uint8_t);
212 const uint8_t* base_ptr = base_array;
213
214 JValue result;
215 ShadowFrame* tmp = ShadowFrame::CreateDeoptimizedFrame(10, nullptr, nullptr, 0);
216
217 int32_t adjusted_length = kBaseLen - sizeof(int32_t);
218 for (int32_t i = 0; i < adjusted_length; ++i) {
219 tmp->SetVRegLong(0, static_cast<int64_t>(reinterpret_cast<intptr_t>(base_ptr + i)));
220
221 UnstartedMemoryPeekInt(self, tmp, &result, 0);
222
223 typedef int32_t unaligned_int __attribute__ ((aligned (1)));
224 const unaligned_int* int_ptr = reinterpret_cast<const unaligned_int*>(base_ptr + i);
225 EXPECT_EQ(result.GetI(), *int_ptr);
226 }
227
228 ShadowFrame::DeleteDeoptimizedFrame(tmp);
229}
230
231TEST_F(UnstartedRuntimeTest, MemoryPeekLong) {
232 Thread* self = Thread::Current();
233
234 ScopedObjectAccess soa(self);
235 constexpr const uint8_t base_array[] = "abcdefghijklmnop";
236 constexpr int32_t kBaseLen = sizeof(base_array) / sizeof(uint8_t);
237 const uint8_t* base_ptr = base_array;
238
239 JValue result;
240 ShadowFrame* tmp = ShadowFrame::CreateDeoptimizedFrame(10, nullptr, nullptr, 0);
241
242 int32_t adjusted_length = kBaseLen - sizeof(int64_t);
243 for (int32_t i = 0; i < adjusted_length; ++i) {
244 tmp->SetVRegLong(0, static_cast<int64_t>(reinterpret_cast<intptr_t>(base_ptr + i)));
245
246 UnstartedMemoryPeekLong(self, tmp, &result, 0);
247
248 typedef int64_t unaligned_long __attribute__ ((aligned (1)));
249 const unaligned_long* long_ptr = reinterpret_cast<const unaligned_long*>(base_ptr + i);
250 EXPECT_EQ(result.GetJ(), *long_ptr);
251 }
252
253 ShadowFrame::DeleteDeoptimizedFrame(tmp);
254}
255
256TEST_F(UnstartedRuntimeTest, StringGetCharsNoCheck) {
257 Thread* self = Thread::Current();
258
259 ScopedObjectAccess soa(self);
260 StackHandleScope<2> hs(self);
261 // TODO: Actual UTF.
262 constexpr const char base_string[] = "abcdefghijklmnop";
263 Handle<mirror::String> h_test_string(hs.NewHandle(
264 mirror::String::AllocFromModifiedUtf8(self, base_string)));
265 constexpr int32_t kBaseLen = sizeof(base_string) / sizeof(char) - 1;
266 Handle<mirror::CharArray> h_char_array(hs.NewHandle(
267 mirror::CharArray::Alloc(self, kBaseLen)));
268 // A buffer so we can make sure we only modify the elements targetted.
269 uint16_t buf[kBaseLen];
270
271 JValue result;
272 ShadowFrame* tmp = ShadowFrame::CreateDeoptimizedFrame(10, nullptr, nullptr, 0);
273
274 for (int32_t start_index = 0; start_index < kBaseLen; ++start_index) {
275 for (int32_t count = 0; count <= kBaseLen; ++count) {
276 for (int32_t trg_offset = 0; trg_offset < kBaseLen; ++trg_offset) {
277 // Only do it when in bounds.
278 if (start_index + count <= kBaseLen && trg_offset + count <= kBaseLen) {
279 tmp->SetVRegReference(0, h_test_string.Get());
280 tmp->SetVReg(1, start_index);
281 tmp->SetVReg(2, count);
282 tmp->SetVRegReference(3, h_char_array.Get());
283 tmp->SetVReg(3, trg_offset);
284
285 // Copy the char_array into buf.
286 memcpy(buf, h_char_array->GetData(), kBaseLen * sizeof(uint16_t));
287
288 UnstartedStringCharAt(self, tmp, &result, 0);
289
290 uint16_t* data = h_char_array->GetData();
291
292 bool success = true;
293
294 // First segment should be unchanged.
295 for (int32_t i = 0; i < trg_offset; ++i) {
296 success = success && (data[i] == buf[i]);
297 }
298 // Second segment should be a copy.
299 for (int32_t i = trg_offset; i < trg_offset + count; ++i) {
300 success = success && (data[i] == buf[i - trg_offset + start_index]);
301 }
302 // Third segment should be unchanged.
303 for (int32_t i = trg_offset + count; i < kBaseLen; ++i) {
304 success = success && (data[i] == buf[i]);
305 }
306
307 EXPECT_TRUE(success);
308 }
309 }
310 }
311 }
312
313 ShadowFrame::DeleteDeoptimizedFrame(tmp);
314}
315
316TEST_F(UnstartedRuntimeTest, StringCharAt) {
317 Thread* self = Thread::Current();
318
319 ScopedObjectAccess soa(self);
320 // TODO: Actual UTF.
321 constexpr const char* base_string = "abcdefghijklmnop";
322 int32_t base_len = static_cast<int32_t>(strlen(base_string));
323 mirror::String* test_string = mirror::String::AllocFromModifiedUtf8(self, base_string);
324
325 JValue result;
326 ShadowFrame* tmp = ShadowFrame::CreateDeoptimizedFrame(10, nullptr, nullptr, 0);
327
328 for (int32_t i = 0; i < base_len; ++i) {
329 tmp->SetVRegReference(0, test_string);
330 tmp->SetVReg(1, i);
331
332 UnstartedStringCharAt(self, tmp, &result, 0);
333
334 EXPECT_EQ(result.GetI(), base_string[i]);
335 }
336
337 ShadowFrame::DeleteDeoptimizedFrame(tmp);
338}
339
Jeff Hao400ce002015-05-29 10:53:17 -0700340TEST_F(UnstartedRuntimeTest, StringInit) {
341 Thread* self = Thread::Current();
342 ScopedObjectAccess soa(self);
343 mirror::Class* klass = mirror::String::GetJavaLangString();
Mathieu Chartiere401d142015-04-22 13:56:20 -0700344 ArtMethod* method = klass->FindDeclaredDirectMethod("<init>", "(Ljava/lang/String;)V",
345 sizeof(void*));
Jeff Hao400ce002015-05-29 10:53:17 -0700346
347 // create instruction data for invoke-direct {v0, v1} of method with fake index
348 uint16_t inst_data[3] = { 0x2070, 0x0000, 0x0010 };
349 const Instruction* inst = Instruction::At(inst_data);
350
351 JValue result;
352 ShadowFrame* shadow_frame = ShadowFrame::CreateDeoptimizedFrame(10, nullptr, method, 0);
353 const char* base_string = "hello_world";
354 mirror::String* string_arg = mirror::String::AllocFromModifiedUtf8(self, base_string);
355 mirror::String* reference_empty_string = mirror::String::AllocFromModifiedUtf8(self, "");
356 shadow_frame->SetVRegReference(0, reference_empty_string);
357 shadow_frame->SetVRegReference(1, string_arg);
358
359 interpreter::DoCall<false, false>(method, self, *shadow_frame, inst, inst_data[0], &result);
360 mirror::String* string_result = reinterpret_cast<mirror::String*>(result.GetL());
361 EXPECT_EQ(string_arg->GetLength(), string_result->GetLength());
362 EXPECT_EQ(memcmp(string_arg->GetValue(), string_result->GetValue(),
363 string_arg->GetLength() * sizeof(uint16_t)), 0);
364
365 ShadowFrame::DeleteDeoptimizedFrame(shadow_frame);
366}
367
Andreas Gampe85a098a2016-03-31 13:30:53 -0700368// Tests the exceptions that should be checked before modifying the destination.
369// (Doesn't check the object vs primitive case ATM.)
370TEST_F(UnstartedRuntimeTest, SystemArrayCopyObjectArrayTestExceptions) {
371 Thread* self = Thread::Current();
372 ScopedObjectAccess soa(self);
373 JValue result;
374 ShadowFrame* tmp = ShadowFrame::CreateDeoptimizedFrame(10, nullptr, nullptr, 0);
375
376 // Note: all tests are not GC safe. Assume there's no GC running here with the few objects we
377 // allocate.
378 StackHandleScope<2> hs_misc(self);
379 Handle<mirror::Class> object_class(
380 hs_misc.NewHandle(mirror::Class::GetJavaLangClass()->GetSuperClass()));
381
382 StackHandleScope<3> hs_data(self);
383 hs_data.NewHandle(mirror::String::AllocFromModifiedUtf8(self, "1"));
384 hs_data.NewHandle(mirror::String::AllocFromModifiedUtf8(self, "2"));
385 hs_data.NewHandle(mirror::String::AllocFromModifiedUtf8(self, "3"));
386
387 Handle<mirror::ObjectArray<mirror::Object>> array(
388 hs_misc.NewHandle(CreateObjectArray(self, object_class.Get(), hs_data)));
389
390 RunArrayCopy(self, tmp, true, array.Get(), -1, array.Get(), 0, 0);
391 RunArrayCopy(self, tmp, true, array.Get(), 0, array.Get(), -1, 0);
392 RunArrayCopy(self, tmp, true, array.Get(), 0, array.Get(), 0, -1);
393 RunArrayCopy(self, tmp, true, array.Get(), 0, array.Get(), 0, 4);
394 RunArrayCopy(self, tmp, true, array.Get(), 0, array.Get(), 1, 3);
395 RunArrayCopy(self, tmp, true, array.Get(), 1, array.Get(), 0, 3);
396
397 mirror::ObjectArray<mirror::Object>* class_as_array =
398 reinterpret_cast<mirror::ObjectArray<mirror::Object>*>(object_class.Get());
399 RunArrayCopy(self, tmp, true, class_as_array, 0, array.Get(), 0, 0);
400 RunArrayCopy(self, tmp, true, array.Get(), 0, class_as_array, 0, 0);
401
402 ShadowFrame::DeleteDeoptimizedFrame(tmp);
403}
404
405TEST_F(UnstartedRuntimeTest, SystemArrayCopyObjectArrayTest) {
406 Thread* self = Thread::Current();
407 ScopedObjectAccess soa(self);
408 JValue result;
409 ShadowFrame* tmp = ShadowFrame::CreateDeoptimizedFrame(10, nullptr, nullptr, 0);
410
411 StackHandleScope<1> hs_object(self);
412 Handle<mirror::Class> object_class(
413 hs_object.NewHandle(mirror::Class::GetJavaLangClass()->GetSuperClass()));
414
415 // Simple test:
416 // [1,2,3]{1 @ 2} into [4,5,6] = [4,2,6]
417 {
418 StackHandleScope<3> hs_src(self);
419 hs_src.NewHandle(mirror::String::AllocFromModifiedUtf8(self, "1"));
420 hs_src.NewHandle(mirror::String::AllocFromModifiedUtf8(self, "2"));
421 hs_src.NewHandle(mirror::String::AllocFromModifiedUtf8(self, "3"));
422
423 StackHandleScope<3> hs_dst(self);
424 hs_dst.NewHandle(mirror::String::AllocFromModifiedUtf8(self, "4"));
425 hs_dst.NewHandle(mirror::String::AllocFromModifiedUtf8(self, "5"));
426 hs_dst.NewHandle(mirror::String::AllocFromModifiedUtf8(self, "6"));
427
428 StackHandleScope<3> hs_expected(self);
429 hs_expected.NewHandle(hs_dst.GetReference(0));
430 hs_expected.NewHandle(hs_dst.GetReference(1));
431 hs_expected.NewHandle(hs_src.GetReference(1));
432
433 RunArrayCopy(self,
434 tmp,
435 false,
436 object_class.Get(),
437 object_class.Get(),
438 hs_src,
439 1,
440 hs_dst,
441 2,
442 1,
443 hs_expected);
444 }
445
446 // Simple test:
447 // [1,2,3]{1 @ 1} into [4,5,6] = [4,2,6] (with dst String[])
448 {
449 StackHandleScope<3> hs_src(self);
450 hs_src.NewHandle(mirror::String::AllocFromModifiedUtf8(self, "1"));
451 hs_src.NewHandle(mirror::String::AllocFromModifiedUtf8(self, "2"));
452 hs_src.NewHandle(mirror::String::AllocFromModifiedUtf8(self, "3"));
453
454 StackHandleScope<3> hs_dst(self);
455 hs_dst.NewHandle(mirror::String::AllocFromModifiedUtf8(self, "4"));
456 hs_dst.NewHandle(mirror::String::AllocFromModifiedUtf8(self, "5"));
457 hs_dst.NewHandle(mirror::String::AllocFromModifiedUtf8(self, "6"));
458
459 StackHandleScope<3> hs_expected(self);
460 hs_expected.NewHandle(hs_dst.GetReference(0));
461 hs_expected.NewHandle(hs_src.GetReference(1));
462 hs_expected.NewHandle(hs_dst.GetReference(2));
463
464 RunArrayCopy(self,
465 tmp,
466 false,
467 object_class.Get(),
468 mirror::String::GetJavaLangString(),
469 hs_src,
470 1,
471 hs_dst,
472 1,
473 1,
474 hs_expected);
475 }
476
477 // Simple test:
478 // [1,*,3] into [4,5,6] = [1,5,6] + exc
479 {
480 StackHandleScope<3> hs_src(self);
481 hs_src.NewHandle(mirror::String::AllocFromModifiedUtf8(self, "1"));
482 hs_src.NewHandle(mirror::String::GetJavaLangString());
483 hs_src.NewHandle(mirror::String::AllocFromModifiedUtf8(self, "3"));
484
485 StackHandleScope<3> hs_dst(self);
486 hs_dst.NewHandle(mirror::String::AllocFromModifiedUtf8(self, "4"));
487 hs_dst.NewHandle(mirror::String::AllocFromModifiedUtf8(self, "5"));
488 hs_dst.NewHandle(mirror::String::AllocFromModifiedUtf8(self, "6"));
489
490 StackHandleScope<3> hs_expected(self);
491 hs_expected.NewHandle(hs_src.GetReference(0));
492 hs_expected.NewHandle(hs_dst.GetReference(1));
493 hs_expected.NewHandle(hs_dst.GetReference(2));
494
495 RunArrayCopy(self,
496 tmp,
497 true,
498 object_class.Get(),
499 mirror::String::GetJavaLangString(),
500 hs_src,
501 0,
502 hs_dst,
503 0,
504 3,
505 hs_expected);
506 }
507
508 ShadowFrame::DeleteDeoptimizedFrame(tmp);
509}
510
Andreas Gampe799681b2015-05-15 19:24:12 -0700511} // namespace interpreter
512} // namespace art