diff options
author | 2016-08-05 11:44:32 +0100 | |
---|---|---|
committer | 2016-08-09 13:47:49 +0100 | |
commit | 14832efeb92334c562ebedef34e920d30e3cee69 (patch) | |
tree | 57d10c24966a46ae1c01861ee579ac6000326c45 /runtime/lambda/closure_test.cc | |
parent | c984725d0035e1925371757c38fed339b409e525 (diff) |
Revert experimental lambda feature.
This is a revert of the following changes :
30c475a2046951a81769c2db0b2dad66cd71e189.
lambda: Minor capture-variable/liberate-variable clean-up after post-merge reviews.
6918bf13eb855b3aa8ccdddda2d27ae8c60cec56.
lambda: Experimental support for capture-variable and liberate-variable
fc1ccd740b7c8e96dfac675cfc580122cd1b40a6.
lambda: Infrastructure to support capture/liberate-variable dex opcodes
e2facc5b18cd756a8b5500fb3d90da69c9ee0fb7.
runtime: Add lambda box/unbox object equality
2ee54e249ad21c74f29a161e248bebe7d22fddf1.
runtime: Partially implement box-lambda and unbox-lambda experimental opcodes
158f35c98e2ec0d40d2c032b8cdce5fb60944a7f.
interpreter: Add experimental lambda opcodes for invoke/create-lambda
a3bb72036f5454e410467f7151dc89f725ae1151.
Added format 25x to dexdump(2).
Plus surrounding cleanups.
Test: make test-art
Change-Id: Ic6f999ad17385ef933f763641049cf721510b202
Diffstat (limited to 'runtime/lambda/closure_test.cc')
-rw-r--r-- | runtime/lambda/closure_test.cc | 356 |
1 files changed, 0 insertions, 356 deletions
diff --git a/runtime/lambda/closure_test.cc b/runtime/lambda/closure_test.cc deleted file mode 100644 index 7c1bd0d591..0000000000 --- a/runtime/lambda/closure_test.cc +++ /dev/null @@ -1,356 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "art_method.h" -#include "lambda/art_lambda_method.h" -#include "lambda/closure.h" -#include "lambda/closure_builder.h" -#include "lambda/closure_builder-inl.h" -#include "utils.h" - -#include <numeric> -#include <stdint.h> -#include <type_traits> -#include "gtest/gtest.h" - -// Turn this on for some extra printfs to help with debugging, since some code is optimized out. -static constexpr const bool kDebuggingClosureTest = true; - -namespace std { - using Closure = art::lambda::Closure; - - // Specialize std::default_delete so it knows how to properly delete closures - // through the way we allocate them in this test. - // - // This is test-only because we don't want the rest of Art to do this. - template <> - struct default_delete<Closure> { - void operator()(Closure* closure) const { - delete[] reinterpret_cast<char*>(closure); - } - }; -} // namespace std - -namespace art { - -// Fake lock acquisition to please clang lock checker. -// This doesn't actually acquire any locks because we don't need multiple threads in this gtest. -struct SCOPED_CAPABILITY ScopedFakeLock { - explicit ScopedFakeLock(MutatorMutex& mu) ACQUIRE(mu) - : mu_(mu) { - } - - ~ScopedFakeLock() RELEASE() - {} - - MutatorMutex& mu_; -}; - -namespace lambda { - -class ClosureTest : public ::testing::Test { - public: - ClosureTest() = default; - ~ClosureTest() = default; - - protected: - static void SetUpTestCase() { - } - - virtual void SetUp() { - // Create a completely dummy method here. - // It's "OK" because the Closure never needs to look inside of the ArtMethod - // (it just needs to be non-null). - uintptr_t ignore = 0xbadbad; - fake_method_ = reinterpret_cast<ArtMethod*>(ignore); - } - - static ::testing::AssertionResult IsResultSuccessful(bool result) { - if (result) { - return ::testing::AssertionSuccess(); - } else { - return ::testing::AssertionFailure(); - } - } - - // Create a closure that captures the static variables from 'args' by-value. - // The lambda method's captured variables types must match the ones in 'args'. - // -- This creates the closure directly in-memory by using memcpy. - template <typename ... Args> - static std::unique_ptr<Closure> CreateClosureStaticVariables(ArtLambdaMethod* lambda_method, - Args&& ... args) { - constexpr size_t header_size = sizeof(ArtLambdaMethod*); - const size_t static_size = GetArgsSize(args ...) + header_size; - EXPECT_GE(static_size, sizeof(Closure)); - - // Can't just 'new' the Closure since we don't know the size up front. - char* closure_as_char_array = new char[static_size]; - Closure* closure_ptr = new (closure_as_char_array) Closure; - - // Set up the data - closure_ptr->lambda_info_ = lambda_method; - CopyArgs(closure_ptr->captured_[0].static_variables_, args ...); - - // Make sure the entire thing is deleted once the unique_ptr goes out of scope. - return std::unique_ptr<Closure>(closure_ptr); // NOLINT [whitespace/braces] [5] - } - - // Copy variadic arguments into the destination array with memcpy. - template <typename T, typename ... Args> - static void CopyArgs(uint8_t destination[], T&& arg, Args&& ... args) { - memcpy(destination, &arg, sizeof(arg)); - CopyArgs(destination + sizeof(arg), args ...); - } - - // Base case: Done. - static void CopyArgs(uint8_t destination[]) { - UNUSED(destination); - } - - // Create a closure that captures the static variables from 'args' by-value. - // The lambda method's captured variables types must match the ones in 'args'. - // -- This uses ClosureBuilder interface to set up the closure indirectly. - template <typename ... Args> - static std::unique_ptr<Closure> CreateClosureStaticVariablesFromBuilder( - ArtLambdaMethod* lambda_method, - Args&& ... args) { - // Acquire a fake lock since closure_builder needs it. - ScopedFakeLock fake_lock(*Locks::mutator_lock_); - - ClosureBuilder closure_builder; - CaptureVariableFromArgsList(/*out*/closure_builder, args ...); - - EXPECT_EQ(sizeof...(args), closure_builder.GetCaptureCount()); - - constexpr size_t header_size = sizeof(ArtLambdaMethod*); - const size_t static_size = GetArgsSize(args ...) + header_size; - EXPECT_GE(static_size, sizeof(Closure)); - - // For static variables, no nested closure, so size must match exactly. - EXPECT_EQ(static_size, closure_builder.GetSize()); - - // Can't just 'new' the Closure since we don't know the size up front. - char* closure_as_char_array = new char[static_size]; - Closure* closure_ptr = new (closure_as_char_array) Closure; - - // The closure builder packs the captured variables into a Closure. - closure_builder.CreateInPlace(closure_ptr, lambda_method); - - // Make sure the entire thing is deleted once the unique_ptr goes out of scope. - return std::unique_ptr<Closure>(closure_ptr); // NOLINT [whitespace/braces] [5] - } - - // Call the correct ClosureBuilder::CaptureVariableXYZ function based on the type of args. - // Invokes for each arg in args. - template <typename ... Args> - static void CaptureVariableFromArgsList(/*out*/ClosureBuilder& closure_builder, Args ... args) { - int ignore[] = { - (CaptureVariableFromArgs(/*out*/closure_builder, args),0)... // NOLINT [whitespace/comma] [3] - }; - UNUSED(ignore); - } - - // ClosureBuilder::CaptureVariablePrimitive for types that are primitive only. - template <typename T> - typename std::enable_if<ShortyFieldTypeTraits::IsPrimitiveType<T>()>::type - static CaptureVariableFromArgs(/*out*/ClosureBuilder& closure_builder, T value) { - static_assert(ShortyFieldTypeTraits::IsPrimitiveType<T>(), "T must be a shorty primitive"); - closure_builder.CaptureVariablePrimitive<T, ShortyFieldTypeSelectEnum<T>::value>(value); - } - - // ClosureBuilder::CaptureVariableObject for types that are objects only. - template <typename T> - typename std::enable_if<ShortyFieldTypeTraits::IsObjectType<T>()>::type - static CaptureVariableFromArgs(/*out*/ClosureBuilder& closure_builder, const T* object) { - ScopedFakeLock fake_lock(*Locks::mutator_lock_); - closure_builder.CaptureVariableObject(object); - } - - // Sum of sizeof(Args...). - template <typename T, typename ... Args> - static constexpr size_t GetArgsSize(T&& arg, Args&& ... args) { - return sizeof(arg) + GetArgsSize(args ...); - } - - // Base case: Done. - static constexpr size_t GetArgsSize() { - return 0; - } - - // Take "U" and memcpy it into a "T". T starts out as (T)0. - template <typename T, typename U> - static T ExpandingBitCast(const U& val) { - static_assert(sizeof(T) >= sizeof(U), "U too large"); - T new_val = static_cast<T>(0); - memcpy(&new_val, &val, sizeof(U)); - return new_val; - } - - // Templatized extraction from closures by checking their type with enable_if. - template <typename T> - static typename std::enable_if<ShortyFieldTypeTraits::IsPrimitiveNarrowType<T>()>::type - ExpectCapturedVariable(const Closure* closure, size_t index, T value) { - EXPECT_EQ(ExpandingBitCast<uint32_t>(value), closure->GetCapturedPrimitiveNarrow(index)) - << " with index " << index; - } - - template <typename T> - static typename std::enable_if<ShortyFieldTypeTraits::IsPrimitiveWideType<T>()>::type - ExpectCapturedVariable(const Closure* closure, size_t index, T value) { - EXPECT_EQ(ExpandingBitCast<uint64_t>(value), closure->GetCapturedPrimitiveWide(index)) - << " with index " << index; - } - - // Templatized SFINAE for Objects so we can get better error messages. - template <typename T> - static typename std::enable_if<ShortyFieldTypeTraits::IsObjectType<T>()>::type - ExpectCapturedVariable(const Closure* closure, size_t index, const T* object) { - EXPECT_EQ(object, closure->GetCapturedObject(index)) - << " with index " << index; - } - - template <typename ... Args> - void TestPrimitive(const char *descriptor, Args ... args) { - const char* shorty = descriptor; - - SCOPED_TRACE(descriptor); - - ASSERT_EQ(strlen(shorty), sizeof...(args)) - << "test error: descriptor must have same # of types as the # of captured variables"; - - // Important: This fake lambda method needs to out-live any Closures we create with it. - ArtLambdaMethod lambda_method{fake_method_, // NOLINT [whitespace/braces] [5] - descriptor, // NOLINT [whitespace/blank_line] [2] - shorty, - }; - - std::unique_ptr<Closure> closure_a; - std::unique_ptr<Closure> closure_b; - - // Test the closure twice when it's constructed in different ways. - { - // Create the closure in a "raw" manner, that is directly with memcpy - // since we know the underlying data format. - // This simulates how the compiler would lay out the data directly. - SCOPED_TRACE("raw closure"); - std::unique_ptr<Closure> closure_raw = CreateClosureStaticVariables(&lambda_method, args ...); - - if (kDebuggingClosureTest) { - std::cerr << "closure raw address: " << closure_raw.get() << std::endl; - } - TestPrimitiveWithClosure(closure_raw.get(), descriptor, shorty, args ...); - closure_a = std::move(closure_raw); - } - - { - // Create the closure with the ClosureBuilder, which is done indirectly. - // This simulates how the interpreter would create the closure dynamically at runtime. - SCOPED_TRACE("closure from builder"); - std::unique_ptr<Closure> closure_built = - CreateClosureStaticVariablesFromBuilder(&lambda_method, args ...); - if (kDebuggingClosureTest) { - std::cerr << "closure built address: " << closure_built.get() << std::endl; - } - TestPrimitiveWithClosure(closure_built.get(), descriptor, shorty, args ...); - closure_b = std::move(closure_built); - } - - // The closures should be identical memory-wise as well. - EXPECT_EQ(closure_a->GetSize(), closure_b->GetSize()); - EXPECT_TRUE(memcmp(closure_a.get(), - closure_b.get(), - std::min(closure_a->GetSize(), closure_b->GetSize())) == 0); - } - - template <typename ... Args> - static void TestPrimitiveWithClosure(Closure* closure, - const char* descriptor, - const char* shorty, - Args ... args) { - EXPECT_EQ(sizeof(ArtLambdaMethod*) + GetArgsSize(args...), closure->GetSize()); - EXPECT_EQ(sizeof...(args), closure->GetNumberOfCapturedVariables()); - EXPECT_STREQ(descriptor, closure->GetCapturedVariablesTypeDescriptor()); - TestPrimitiveExpects(closure, shorty, /*index*/0, args ...); - } - - // Call EXPECT_EQ for each argument in the closure's #GetCapturedX. - template <typename T, typename ... Args> - static void TestPrimitiveExpects( - const Closure* closure, const char* shorty, size_t index, T arg, Args ... args) { - ASSERT_EQ(ShortyFieldType(shorty[index]).GetStaticSize(), sizeof(T)) - << "Test error: Type mismatch at index " << index; - ExpectCapturedVariable(closure, index, arg); - EXPECT_EQ(ShortyFieldType(shorty[index]), closure->GetCapturedShortyType(index)); - TestPrimitiveExpects(closure, shorty, index + 1, args ...); - } - - // Base case for EXPECT_EQ. - static void TestPrimitiveExpects(const Closure* closure, const char* shorty, size_t index) { - UNUSED(closure, shorty, index); - } - - ArtMethod* fake_method_; -}; - -TEST_F(ClosureTest, TestTrivial) { - ArtLambdaMethod lambda_method{fake_method_, // NOLINT [whitespace/braces] [5] - "", // No captured variables // NOLINT [whitespace/blank_line] [2] - "", // No captured variables - }; - - std::unique_ptr<Closure> closure = CreateClosureStaticVariables(&lambda_method); - - EXPECT_EQ(sizeof(ArtLambdaMethod*), closure->GetSize()); - EXPECT_EQ(0u, closure->GetNumberOfCapturedVariables()); -} // TEST_F - -TEST_F(ClosureTest, TestPrimitiveSingle) { - TestPrimitive("Z", true); - TestPrimitive("B", int8_t(0xde)); - TestPrimitive("C", uint16_t(0xbeef)); - TestPrimitive("S", int16_t(0xdead)); - TestPrimitive("I", int32_t(0xdeadbeef)); - TestPrimitive("F", 0.123f); - TestPrimitive("J", int64_t(0xdeadbeef00c0ffee)); - TestPrimitive("D", 123.456); -} // TEST_F - -TEST_F(ClosureTest, TestPrimitiveMany) { - TestPrimitive("ZZ", true, false); - TestPrimitive("ZZZ", true, false, true); - TestPrimitive("BBBB", int8_t(0xde), int8_t(0xa0), int8_t(0xff), int8_t(0xcc)); - TestPrimitive("CC", uint16_t(0xbeef), uint16_t(0xdead)); - TestPrimitive("SSSS", int16_t(0xdead), int16_t(0xc0ff), int16_t(0xf000), int16_t(0xbaba)); - TestPrimitive("III", int32_t(0xdeadbeef), int32_t(0xc0ffee), int32_t(0xbeefdead)); - TestPrimitive("FF", 0.123f, 555.666f); - TestPrimitive("JJJ", int64_t(0xdeadbeef00c0ffee), int64_t(0x123), int64_t(0xc0ffee)); - TestPrimitive("DD", 123.456, 777.888); -} // TEST_F - -TEST_F(ClosureTest, TestPrimitiveMixed) { - TestPrimitive("ZZBBCCSSIIFFJJDD", - true, false, - int8_t(0xde), int8_t(0xa0), - uint16_t(0xbeef), uint16_t(0xdead), - int16_t(0xdead), int16_t(0xc0ff), - int32_t(0xdeadbeef), int32_t(0xc0ffee), - 0.123f, 555.666f, - int64_t(0xdeadbeef00c0ffee), int64_t(0x123), - 123.456, 777.888); -} // TEST_F - -} // namespace lambda -} // namespace art |