Home | History | Annotate | Download | only in lambda
      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