• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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> {
operator ()std::default_delete41     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 {
ACQUIREart::ScopedFakeLock52   explicit ScopedFakeLock(MutatorMutex& mu) ACQUIRE(mu)
53       : mu_(mu) {
54   }
55 
RELEASEart::ScopedFakeLock56   ~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:
SetUpTestCase()70   static void SetUpTestCase() {
71   }
72 
SetUp()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 
IsResultSuccessful(bool result)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>
CreateClosureStaticVariables(ArtLambdaMethod * lambda_method,Args &&...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>
CopyArgs(uint8_t destination[],T && arg,Args &&...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.
CopyArgs(uint8_t destination[])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>
CreateClosureStaticVariablesFromBuilder(ArtLambdaMethod * lambda_method,Args &&...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>
CaptureVariableFromArgsList(ClosureBuilder & closure_builder,Args...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
CaptureVariableFromArgs(ClosureBuilder & closure_builder,T value)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
CaptureVariableFromArgs(ClosureBuilder & closure_builder,const T * object)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>
GetArgsSize(T && arg,Args &&...args)184   static constexpr size_t GetArgsSize(T&& arg, Args&& ... args) {
185     return sizeof(arg) + GetArgsSize(args ...);
186   }
187 
188   // Base case: Done.
GetArgsSize()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>
ExpandingBitCast(const U & val)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
ExpectCapturedVariable(const Closure * closure,size_t index,T value)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
ExpectCapturedVariable(const Closure * closure,size_t index,T value)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
ExpectCapturedVariable(const Closure * closure,size_t index,const T * object)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>
TestPrimitive(const char * descriptor,Args...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>
TestPrimitiveWithClosure(Closure * closure,const char * descriptor,const char * shorty,Args...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>
TestPrimitiveExpects(const Closure * closure,const char * shorty,size_t index,T arg,Args...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.
TestPrimitiveExpects(const Closure * closure,const char * shorty,size_t index)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 
TEST_F(ClosureTest,TestTrivial)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 
TEST_F(ClosureTest,TestPrimitiveSingle)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 
TEST_F(ClosureTest,TestPrimitiveMany)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 
TEST_F(ClosureTest,TestPrimitiveMixed)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