Andreas Gampe | 799681b | 2015-05-15 19:24:12 -0700 | [diff] [blame] | 1 | /* |
| 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" |
| 21 | #include "handle.h" |
| 22 | #include "handle_scope-inl.h" |
| 23 | #include "mirror/class_loader.h" |
| 24 | #include "mirror/string-inl.h" |
| 25 | #include "runtime.h" |
| 26 | #include "scoped_thread_state_change.h" |
| 27 | #include "thread.h" |
| 28 | |
| 29 | namespace art { |
| 30 | namespace interpreter { |
| 31 | |
| 32 | class UnstartedRuntimeTest : public CommonRuntimeTest { |
| 33 | protected: |
| 34 | // Re-expose all UnstartedRuntime implementations so we don't need to declare a million |
| 35 | // test friends. |
| 36 | |
| 37 | // Methods that intercept available libcore implementations. |
| 38 | #define UNSTARTED_DIRECT(Name, SigIgnored) \ |
| 39 | static void Unstarted ## Name(Thread* self, \ |
| 40 | ShadowFrame* shadow_frame, \ |
| 41 | JValue* result, \ |
| 42 | size_t arg_offset) \ |
| 43 | SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { \ |
| 44 | interpreter::UnstartedRuntime::Unstarted ## Name(self, shadow_frame, result, arg_offset); \ |
| 45 | } |
| 46 | #include "unstarted_runtime_list.h" |
| 47 | UNSTARTED_RUNTIME_DIRECT_LIST(UNSTARTED_DIRECT) |
| 48 | #undef UNSTARTED_RUNTIME_DIRECT_LIST |
| 49 | #undef UNSTARTED_RUNTIME_JNI_LIST |
| 50 | #undef UNSTARTED_DIRECT |
| 51 | |
| 52 | // Methods that are native. |
| 53 | #define UNSTARTED_JNI(Name, SigIgnored) \ |
| 54 | static void UnstartedJNI ## Name(Thread* self, \ |
| 55 | mirror::ArtMethod* method, \ |
| 56 | mirror::Object* receiver, \ |
| 57 | uint32_t* args, \ |
| 58 | JValue* result) \ |
| 59 | SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { \ |
| 60 | interpreter::UnstartedRuntime::UnstartedJNI ## Name(self, method, receiver, args, result); \ |
| 61 | } |
| 62 | #include "unstarted_runtime_list.h" |
| 63 | UNSTARTED_RUNTIME_JNI_LIST(UNSTARTED_JNI) |
| 64 | #undef UNSTARTED_RUNTIME_DIRECT_LIST |
| 65 | #undef UNSTARTED_RUNTIME_JNI_LIST |
| 66 | #undef UNSTARTED_JNI |
| 67 | }; |
| 68 | |
| 69 | TEST_F(UnstartedRuntimeTest, MemoryPeekByte) { |
| 70 | Thread* self = Thread::Current(); |
| 71 | |
| 72 | ScopedObjectAccess soa(self); |
| 73 | constexpr const uint8_t base_array[] = "abcdefghijklmnop"; |
| 74 | constexpr int32_t kBaseLen = sizeof(base_array) / sizeof(uint8_t); |
| 75 | const uint8_t* base_ptr = base_array; |
| 76 | |
| 77 | JValue result; |
| 78 | ShadowFrame* tmp = ShadowFrame::CreateDeoptimizedFrame(10, nullptr, nullptr, 0); |
| 79 | |
| 80 | for (int32_t i = 0; i < kBaseLen; ++i) { |
| 81 | tmp->SetVRegLong(0, static_cast<int64_t>(reinterpret_cast<intptr_t>(base_ptr + i))); |
| 82 | |
| 83 | UnstartedMemoryPeekByte(self, tmp, &result, 0); |
| 84 | |
| 85 | EXPECT_EQ(result.GetB(), static_cast<int8_t>(base_array[i])); |
| 86 | } |
| 87 | |
| 88 | ShadowFrame::DeleteDeoptimizedFrame(tmp); |
| 89 | } |
| 90 | |
| 91 | TEST_F(UnstartedRuntimeTest, MemoryPeekShort) { |
| 92 | Thread* self = Thread::Current(); |
| 93 | |
| 94 | ScopedObjectAccess soa(self); |
| 95 | constexpr const uint8_t base_array[] = "abcdefghijklmnop"; |
| 96 | constexpr int32_t kBaseLen = sizeof(base_array) / sizeof(uint8_t); |
| 97 | const uint8_t* base_ptr = base_array; |
| 98 | |
| 99 | JValue result; |
| 100 | ShadowFrame* tmp = ShadowFrame::CreateDeoptimizedFrame(10, nullptr, nullptr, 0); |
| 101 | |
| 102 | int32_t adjusted_length = kBaseLen - sizeof(int16_t); |
| 103 | for (int32_t i = 0; i < adjusted_length; ++i) { |
| 104 | tmp->SetVRegLong(0, static_cast<int64_t>(reinterpret_cast<intptr_t>(base_ptr + i))); |
| 105 | |
| 106 | UnstartedMemoryPeekShort(self, tmp, &result, 0); |
| 107 | |
| 108 | typedef int16_t unaligned_short __attribute__ ((aligned (1))); |
| 109 | const unaligned_short* short_ptr = reinterpret_cast<const unaligned_short*>(base_ptr + i); |
| 110 | EXPECT_EQ(result.GetS(), *short_ptr); |
| 111 | } |
| 112 | |
| 113 | ShadowFrame::DeleteDeoptimizedFrame(tmp); |
| 114 | } |
| 115 | |
| 116 | TEST_F(UnstartedRuntimeTest, MemoryPeekInt) { |
| 117 | Thread* self = Thread::Current(); |
| 118 | |
| 119 | ScopedObjectAccess soa(self); |
| 120 | constexpr const uint8_t base_array[] = "abcdefghijklmnop"; |
| 121 | constexpr int32_t kBaseLen = sizeof(base_array) / sizeof(uint8_t); |
| 122 | const uint8_t* base_ptr = base_array; |
| 123 | |
| 124 | JValue result; |
| 125 | ShadowFrame* tmp = ShadowFrame::CreateDeoptimizedFrame(10, nullptr, nullptr, 0); |
| 126 | |
| 127 | int32_t adjusted_length = kBaseLen - sizeof(int32_t); |
| 128 | for (int32_t i = 0; i < adjusted_length; ++i) { |
| 129 | tmp->SetVRegLong(0, static_cast<int64_t>(reinterpret_cast<intptr_t>(base_ptr + i))); |
| 130 | |
| 131 | UnstartedMemoryPeekInt(self, tmp, &result, 0); |
| 132 | |
| 133 | typedef int32_t unaligned_int __attribute__ ((aligned (1))); |
| 134 | const unaligned_int* int_ptr = reinterpret_cast<const unaligned_int*>(base_ptr + i); |
| 135 | EXPECT_EQ(result.GetI(), *int_ptr); |
| 136 | } |
| 137 | |
| 138 | ShadowFrame::DeleteDeoptimizedFrame(tmp); |
| 139 | } |
| 140 | |
| 141 | TEST_F(UnstartedRuntimeTest, MemoryPeekLong) { |
| 142 | Thread* self = Thread::Current(); |
| 143 | |
| 144 | ScopedObjectAccess soa(self); |
| 145 | constexpr const uint8_t base_array[] = "abcdefghijklmnop"; |
| 146 | constexpr int32_t kBaseLen = sizeof(base_array) / sizeof(uint8_t); |
| 147 | const uint8_t* base_ptr = base_array; |
| 148 | |
| 149 | JValue result; |
| 150 | ShadowFrame* tmp = ShadowFrame::CreateDeoptimizedFrame(10, nullptr, nullptr, 0); |
| 151 | |
| 152 | int32_t adjusted_length = kBaseLen - sizeof(int64_t); |
| 153 | for (int32_t i = 0; i < adjusted_length; ++i) { |
| 154 | tmp->SetVRegLong(0, static_cast<int64_t>(reinterpret_cast<intptr_t>(base_ptr + i))); |
| 155 | |
| 156 | UnstartedMemoryPeekLong(self, tmp, &result, 0); |
| 157 | |
| 158 | typedef int64_t unaligned_long __attribute__ ((aligned (1))); |
| 159 | const unaligned_long* long_ptr = reinterpret_cast<const unaligned_long*>(base_ptr + i); |
| 160 | EXPECT_EQ(result.GetJ(), *long_ptr); |
| 161 | } |
| 162 | |
| 163 | ShadowFrame::DeleteDeoptimizedFrame(tmp); |
| 164 | } |
| 165 | |
| 166 | TEST_F(UnstartedRuntimeTest, StringGetCharsNoCheck) { |
| 167 | Thread* self = Thread::Current(); |
| 168 | |
| 169 | ScopedObjectAccess soa(self); |
| 170 | StackHandleScope<2> hs(self); |
| 171 | // TODO: Actual UTF. |
| 172 | constexpr const char base_string[] = "abcdefghijklmnop"; |
| 173 | Handle<mirror::String> h_test_string(hs.NewHandle( |
| 174 | mirror::String::AllocFromModifiedUtf8(self, base_string))); |
| 175 | constexpr int32_t kBaseLen = sizeof(base_string) / sizeof(char) - 1; |
| 176 | Handle<mirror::CharArray> h_char_array(hs.NewHandle( |
| 177 | mirror::CharArray::Alloc(self, kBaseLen))); |
| 178 | // A buffer so we can make sure we only modify the elements targetted. |
| 179 | uint16_t buf[kBaseLen]; |
| 180 | |
| 181 | JValue result; |
| 182 | ShadowFrame* tmp = ShadowFrame::CreateDeoptimizedFrame(10, nullptr, nullptr, 0); |
| 183 | |
| 184 | for (int32_t start_index = 0; start_index < kBaseLen; ++start_index) { |
| 185 | for (int32_t count = 0; count <= kBaseLen; ++count) { |
| 186 | for (int32_t trg_offset = 0; trg_offset < kBaseLen; ++trg_offset) { |
| 187 | // Only do it when in bounds. |
| 188 | if (start_index + count <= kBaseLen && trg_offset + count <= kBaseLen) { |
| 189 | tmp->SetVRegReference(0, h_test_string.Get()); |
| 190 | tmp->SetVReg(1, start_index); |
| 191 | tmp->SetVReg(2, count); |
| 192 | tmp->SetVRegReference(3, h_char_array.Get()); |
| 193 | tmp->SetVReg(3, trg_offset); |
| 194 | |
| 195 | // Copy the char_array into buf. |
| 196 | memcpy(buf, h_char_array->GetData(), kBaseLen * sizeof(uint16_t)); |
| 197 | |
| 198 | UnstartedStringCharAt(self, tmp, &result, 0); |
| 199 | |
| 200 | uint16_t* data = h_char_array->GetData(); |
| 201 | |
| 202 | bool success = true; |
| 203 | |
| 204 | // First segment should be unchanged. |
| 205 | for (int32_t i = 0; i < trg_offset; ++i) { |
| 206 | success = success && (data[i] == buf[i]); |
| 207 | } |
| 208 | // Second segment should be a copy. |
| 209 | for (int32_t i = trg_offset; i < trg_offset + count; ++i) { |
| 210 | success = success && (data[i] == buf[i - trg_offset + start_index]); |
| 211 | } |
| 212 | // Third segment should be unchanged. |
| 213 | for (int32_t i = trg_offset + count; i < kBaseLen; ++i) { |
| 214 | success = success && (data[i] == buf[i]); |
| 215 | } |
| 216 | |
| 217 | EXPECT_TRUE(success); |
| 218 | } |
| 219 | } |
| 220 | } |
| 221 | } |
| 222 | |
| 223 | ShadowFrame::DeleteDeoptimizedFrame(tmp); |
| 224 | } |
| 225 | |
| 226 | TEST_F(UnstartedRuntimeTest, StringCharAt) { |
| 227 | Thread* self = Thread::Current(); |
| 228 | |
| 229 | ScopedObjectAccess soa(self); |
| 230 | // TODO: Actual UTF. |
| 231 | constexpr const char* base_string = "abcdefghijklmnop"; |
| 232 | int32_t base_len = static_cast<int32_t>(strlen(base_string)); |
| 233 | mirror::String* test_string = mirror::String::AllocFromModifiedUtf8(self, base_string); |
| 234 | |
| 235 | JValue result; |
| 236 | ShadowFrame* tmp = ShadowFrame::CreateDeoptimizedFrame(10, nullptr, nullptr, 0); |
| 237 | |
| 238 | for (int32_t i = 0; i < base_len; ++i) { |
| 239 | tmp->SetVRegReference(0, test_string); |
| 240 | tmp->SetVReg(1, i); |
| 241 | |
| 242 | UnstartedStringCharAt(self, tmp, &result, 0); |
| 243 | |
| 244 | EXPECT_EQ(result.GetI(), base_string[i]); |
| 245 | } |
| 246 | |
| 247 | ShadowFrame::DeleteDeoptimizedFrame(tmp); |
| 248 | } |
| 249 | |
| 250 | } // namespace interpreter |
| 251 | } // namespace art |