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 "art_method.h" 18 #include "lambda/art_lambda_method.h" 19 #include "lambda/closure.h" 20 #include "lambda/closure_builder.h" 21 #include "lambda/closure_builder-inl.h" 22 #include "utils.h" 23 24 #include <numeric> 25 #include <stdint.h> 26 #include <type_traits> 27 #include "gtest/gtest.h" 28 29 // Turn this on for some extra printfs to help with debugging, since some code is optimized out. 30 static constexpr const bool kDebuggingClosureTest = true; 31 32 namespace std { 33 using Closure = art::lambda::Closure; 34 35 // Specialize std::default_delete so it knows how to properly delete closures 36 // through the way we allocate them in this test. 37 // 38 // This is test-only because we don't want the rest of Art to do this. 39 template <> 40 struct default_delete<Closure> { 41 void operator()(Closure* closure) const { 42 delete[] reinterpret_cast<char*>(closure); 43 } 44 }; 45 } // namespace std 46 47 namespace art { 48 49 // Fake lock acquisition to please clang lock checker. 50 // This doesn't actually acquire any locks because we don't need multiple threads in this gtest. 51 struct SCOPED_CAPABILITY ScopedFakeLock { 52 explicit ScopedFakeLock(MutatorMutex& mu) ACQUIRE(mu) 53 : mu_(mu) { 54 } 55 56 ~ScopedFakeLock() RELEASE() 57 {} 58 59 MutatorMutex& mu_; 60 }; 61 62 namespace lambda { 63 64 class ClosureTest : public ::testing::Test { 65 public: 66 ClosureTest() = default; 67 ~ClosureTest() = default; 68 69 protected: 70 static void SetUpTestCase() { 71 } 72 73 virtual void SetUp() { 74 // Create a completely dummy method here. 75 // It's "OK" because the Closure never needs to look inside of the ArtMethod 76 // (it just needs to be non-null). 77 uintptr_t ignore = 0xbadbad; 78 fake_method_ = reinterpret_cast<ArtMethod*>(ignore); 79 } 80 81 static ::testing::AssertionResult IsResultSuccessful(bool result) { 82 if (result) { 83 return ::testing::AssertionSuccess(); 84 } else { 85 return ::testing::AssertionFailure(); 86 } 87 } 88 89 // Create a closure that captures the static variables from 'args' by-value. 90 // The lambda method's captured variables types must match the ones in 'args'. 91 // -- This creates the closure directly in-memory by using memcpy. 92 template <typename ... Args> 93 static std::unique_ptr<Closure> CreateClosureStaticVariables(ArtLambdaMethod* lambda_method, 94 Args&& ... args) { 95 constexpr size_t header_size = sizeof(ArtLambdaMethod*); 96 const size_t static_size = GetArgsSize(args ...) + header_size; 97 EXPECT_GE(static_size, sizeof(Closure)); 98 99 // Can't just 'new' the Closure since we don't know the size up front. 100 char* closure_as_char_array = new char[static_size]; 101 Closure* closure_ptr = new (closure_as_char_array) Closure; 102 103 // Set up the data 104 closure_ptr->lambda_info_ = lambda_method; 105 CopyArgs(closure_ptr->captured_[0].static_variables_, args ...); 106 107 // Make sure the entire thing is deleted once the unique_ptr goes out of scope. 108 return std::unique_ptr<Closure>(closure_ptr); // NOLINT [whitespace/braces] [5] 109 } 110 111 // Copy variadic arguments into the destination array with memcpy. 112 template <typename T, typename ... Args> 113 static void CopyArgs(uint8_t destination[], T&& arg, Args&& ... args) { 114 memcpy(destination, &arg, sizeof(arg)); 115 CopyArgs(destination + sizeof(arg), args ...); 116 } 117 118 // Base case: Done. 119 static void CopyArgs(uint8_t destination[]) { 120 UNUSED(destination); 121 } 122 123 // Create a closure that captures the static variables from 'args' by-value. 124 // The lambda method's captured variables types must match the ones in 'args'. 125 // -- This uses ClosureBuilder interface to set up the closure indirectly. 126 template <typename ... Args> 127 static std::unique_ptr<Closure> CreateClosureStaticVariablesFromBuilder( 128 ArtLambdaMethod* lambda_method, 129 Args&& ... args) { 130 // Acquire a fake lock since closure_builder needs it. 131 ScopedFakeLock fake_lock(*Locks::mutator_lock_); 132 133 ClosureBuilder closure_builder; 134 CaptureVariableFromArgsList(/*out*/closure_builder, args ...); 135 136 EXPECT_EQ(sizeof...(args), closure_builder.GetCaptureCount()); 137 138 constexpr size_t header_size = sizeof(ArtLambdaMethod*); 139 const size_t static_size = GetArgsSize(args ...) + header_size; 140 EXPECT_GE(static_size, sizeof(Closure)); 141 142 // For static variables, no nested closure, so size must match exactly. 143 EXPECT_EQ(static_size, closure_builder.GetSize()); 144 145 // Can't just 'new' the Closure since we don't know the size up front. 146 char* closure_as_char_array = new char[static_size]; 147 Closure* closure_ptr = new (closure_as_char_array) Closure; 148 149 // The closure builder packs the captured variables into a Closure. 150 closure_builder.CreateInPlace(closure_ptr, lambda_method); 151 152 // Make sure the entire thing is deleted once the unique_ptr goes out of scope. 153 return std::unique_ptr<Closure>(closure_ptr); // NOLINT [whitespace/braces] [5] 154 } 155 156 // Call the correct ClosureBuilder::CaptureVariableXYZ function based on the type of args. 157 // Invokes for each arg in args. 158 template <typename ... Args> 159 static void CaptureVariableFromArgsList(/*out*/ClosureBuilder& closure_builder, Args ... args) { 160 int ignore[] = { 161 (CaptureVariableFromArgs(/*out*/closure_builder, args),0)... // NOLINT [whitespace/comma] [3] 162 }; 163 UNUSED(ignore); 164 } 165 166 // ClosureBuilder::CaptureVariablePrimitive for types that are primitive only. 167 template <typename T> 168 typename std::enable_if<ShortyFieldTypeTraits::IsPrimitiveType<T>()>::type 169 static CaptureVariableFromArgs(/*out*/ClosureBuilder& closure_builder, T value) { 170 static_assert(ShortyFieldTypeTraits::IsPrimitiveType<T>(), "T must be a shorty primitive"); 171 closure_builder.CaptureVariablePrimitive<T, ShortyFieldTypeSelectEnum<T>::value>(value); 172 } 173 174 // ClosureBuilder::CaptureVariableObject for types that are objects only. 175 template <typename T> 176 typename std::enable_if<ShortyFieldTypeTraits::IsObjectType<T>()>::type 177 static CaptureVariableFromArgs(/*out*/ClosureBuilder& closure_builder, const T* object) { 178 ScopedFakeLock fake_lock(*Locks::mutator_lock_); 179 closure_builder.CaptureVariableObject(object); 180 } 181 182 // Sum of sizeof(Args...). 183 template <typename T, typename ... Args> 184 static constexpr size_t GetArgsSize(T&& arg, Args&& ... args) { 185 return sizeof(arg) + GetArgsSize(args ...); 186 } 187 188 // Base case: Done. 189 static constexpr size_t GetArgsSize() { 190 return 0; 191 } 192 193 // Take "U" and memcpy it into a "T". T starts out as (T)0. 194 template <typename T, typename U> 195 static T ExpandingBitCast(const U& val) { 196 static_assert(sizeof(T) >= sizeof(U), "U too large"); 197 T new_val = static_cast<T>(0); 198 memcpy(&new_val, &val, sizeof(U)); 199 return new_val; 200 } 201 202 // Templatized extraction from closures by checking their type with enable_if. 203 template <typename T> 204 static typename std::enable_if<ShortyFieldTypeTraits::IsPrimitiveNarrowType<T>()>::type 205 ExpectCapturedVariable(const Closure* closure, size_t index, T value) { 206 EXPECT_EQ(ExpandingBitCast<uint32_t>(value), closure->GetCapturedPrimitiveNarrow(index)) 207 << " with index " << index; 208 } 209 210 template <typename T> 211 static typename std::enable_if<ShortyFieldTypeTraits::IsPrimitiveWideType<T>()>::type 212 ExpectCapturedVariable(const Closure* closure, size_t index, T value) { 213 EXPECT_EQ(ExpandingBitCast<uint64_t>(value), closure->GetCapturedPrimitiveWide(index)) 214 << " with index " << index; 215 } 216 217 // Templatized SFINAE for Objects so we can get better error messages. 218 template <typename T> 219 static typename std::enable_if<ShortyFieldTypeTraits::IsObjectType<T>()>::type 220 ExpectCapturedVariable(const Closure* closure, size_t index, const T* object) { 221 EXPECT_EQ(object, closure->GetCapturedObject(index)) 222 << " with index " << index; 223 } 224 225 template <typename ... Args> 226 void TestPrimitive(const char *descriptor, Args ... args) { 227 const char* shorty = descriptor; 228 229 SCOPED_TRACE(descriptor); 230 231 ASSERT_EQ(strlen(shorty), sizeof...(args)) 232 << "test error: descriptor must have same # of types as the # of captured variables"; 233 234 // Important: This fake lambda method needs to out-live any Closures we create with it. 235 ArtLambdaMethod lambda_method{fake_method_, // NOLINT [whitespace/braces] [5] 236 descriptor, // NOLINT [whitespace/blank_line] [2] 237 shorty, 238 }; 239 240 std::unique_ptr<Closure> closure_a; 241 std::unique_ptr<Closure> closure_b; 242 243 // Test the closure twice when it's constructed in different ways. 244 { 245 // Create the closure in a "raw" manner, that is directly with memcpy 246 // since we know the underlying data format. 247 // This simulates how the compiler would lay out the data directly. 248 SCOPED_TRACE("raw closure"); 249 std::unique_ptr<Closure> closure_raw = CreateClosureStaticVariables(&lambda_method, args ...); 250 251 if (kDebuggingClosureTest) { 252 std::cerr << "closure raw address: " << closure_raw.get() << std::endl; 253 } 254 TestPrimitiveWithClosure(closure_raw.get(), descriptor, shorty, args ...); 255 closure_a = std::move(closure_raw); 256 } 257 258 { 259 // Create the closure with the ClosureBuilder, which is done indirectly. 260 // This simulates how the interpreter would create the closure dynamically at runtime. 261 SCOPED_TRACE("closure from builder"); 262 std::unique_ptr<Closure> closure_built = 263 CreateClosureStaticVariablesFromBuilder(&lambda_method, args ...); 264 if (kDebuggingClosureTest) { 265 std::cerr << "closure built address: " << closure_built.get() << std::endl; 266 } 267 TestPrimitiveWithClosure(closure_built.get(), descriptor, shorty, args ...); 268 closure_b = std::move(closure_built); 269 } 270 271 // The closures should be identical memory-wise as well. 272 EXPECT_EQ(closure_a->GetSize(), closure_b->GetSize()); 273 EXPECT_TRUE(memcmp(closure_a.get(), 274 closure_b.get(), 275 std::min(closure_a->GetSize(), closure_b->GetSize())) == 0); 276 } 277 278 template <typename ... Args> 279 static void TestPrimitiveWithClosure(Closure* closure, 280 const char* descriptor, 281 const char* shorty, 282 Args ... args) { 283 EXPECT_EQ(sizeof(ArtLambdaMethod*) + GetArgsSize(args...), closure->GetSize()); 284 EXPECT_EQ(sizeof...(args), closure->GetNumberOfCapturedVariables()); 285 EXPECT_STREQ(descriptor, closure->GetCapturedVariablesTypeDescriptor()); 286 TestPrimitiveExpects(closure, shorty, /*index*/0, args ...); 287 } 288 289 // Call EXPECT_EQ for each argument in the closure's #GetCapturedX. 290 template <typename T, typename ... Args> 291 static void TestPrimitiveExpects( 292 const Closure* closure, const char* shorty, size_t index, T arg, Args ... args) { 293 ASSERT_EQ(ShortyFieldType(shorty[index]).GetStaticSize(), sizeof(T)) 294 << "Test error: Type mismatch at index " << index; 295 ExpectCapturedVariable(closure, index, arg); 296 EXPECT_EQ(ShortyFieldType(shorty[index]), closure->GetCapturedShortyType(index)); 297 TestPrimitiveExpects(closure, shorty, index + 1, args ...); 298 } 299 300 // Base case for EXPECT_EQ. 301 static void TestPrimitiveExpects(const Closure* closure, const char* shorty, size_t index) { 302 UNUSED(closure, shorty, index); 303 } 304 305 ArtMethod* fake_method_; 306 }; 307 308 TEST_F(ClosureTest, TestTrivial) { 309 ArtLambdaMethod lambda_method{fake_method_, // NOLINT [whitespace/braces] [5] 310 "", // No captured variables // NOLINT [whitespace/blank_line] [2] 311 "", // No captured variables 312 }; 313 314 std::unique_ptr<Closure> closure = CreateClosureStaticVariables(&lambda_method); 315 316 EXPECT_EQ(sizeof(ArtLambdaMethod*), closure->GetSize()); 317 EXPECT_EQ(0u, closure->GetNumberOfCapturedVariables()); 318 } // TEST_F 319 320 TEST_F(ClosureTest, TestPrimitiveSingle) { 321 TestPrimitive("Z", true); 322 TestPrimitive("B", int8_t(0xde)); 323 TestPrimitive("C", uint16_t(0xbeef)); 324 TestPrimitive("S", int16_t(0xdead)); 325 TestPrimitive("I", int32_t(0xdeadbeef)); 326 TestPrimitive("F", 0.123f); 327 TestPrimitive("J", int64_t(0xdeadbeef00c0ffee)); 328 TestPrimitive("D", 123.456); 329 } // TEST_F 330 331 TEST_F(ClosureTest, TestPrimitiveMany) { 332 TestPrimitive("ZZ", true, false); 333 TestPrimitive("ZZZ", true, false, true); 334 TestPrimitive("BBBB", int8_t(0xde), int8_t(0xa0), int8_t(0xff), int8_t(0xcc)); 335 TestPrimitive("CC", uint16_t(0xbeef), uint16_t(0xdead)); 336 TestPrimitive("SSSS", int16_t(0xdead), int16_t(0xc0ff), int16_t(0xf000), int16_t(0xbaba)); 337 TestPrimitive("III", int32_t(0xdeadbeef), int32_t(0xc0ffee), int32_t(0xbeefdead)); 338 TestPrimitive("FF", 0.123f, 555.666f); 339 TestPrimitive("JJJ", int64_t(0xdeadbeef00c0ffee), int64_t(0x123), int64_t(0xc0ffee)); 340 TestPrimitive("DD", 123.456, 777.888); 341 } // TEST_F 342 343 TEST_F(ClosureTest, TestPrimitiveMixed) { 344 TestPrimitive("ZZBBCCSSIIFFJJDD", 345 true, false, 346 int8_t(0xde), int8_t(0xa0), 347 uint16_t(0xbeef), uint16_t(0xdead), 348 int16_t(0xdead), int16_t(0xc0ff), 349 int32_t(0xdeadbeef), int32_t(0xc0ffee), 350 0.123f, 555.666f, 351 int64_t(0xdeadbeef00c0ffee), int64_t(0x123), 352 123.456, 777.888); 353 } // TEST_F 354 355 } // namespace lambda 356 } // namespace art 357