blob: 7c1bd0d5917393a8d040b30b1e5126b76ba35fc7 [file] [log] [blame]
Igor Murashkinfc1ccd72015-07-30 15:11:09 -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 "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.
30static constexpr const bool kDebuggingClosureTest = true;
31
32namespace 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
47namespace 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.
51struct 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
62namespace lambda {
63
64class 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
308TEST_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
320TEST_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
331TEST_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
343TEST_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