summaryrefslogtreecommitdiff
path: root/runtime/lambda/closure_test.cc
diff options
context:
space:
mode:
author Narayan Kamath <narayan@google.com> 2016-08-05 11:44:32 +0100
committer Narayan Kamath <narayan@google.com> 2016-08-09 13:47:49 +0100
commit14832efeb92334c562ebedef34e920d30e3cee69 (patch)
tree57d10c24966a46ae1c01861ee579ac6000326c45 /runtime/lambda/closure_test.cc
parentc984725d0035e1925371757c38fed339b409e525 (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.cc356
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