lambda: Infrastructure to support capture/liberate-variable dex opcodes

* ArtLambdaMethod - wrap an ArtMethod with extra runtime lambda info
* Closure - data representation for a runtime lambda closure (read-only)
* ClosureBuilder - writer for creating a Closure at runtime
* ShortyFieldType - char/enum wrapper for shorty_field_type in dex

Tests:
* Closure, ClosureBuilder, ShortyFieldType have full unit test coverage.
* ArtLambdaMethod does not, but it is tested indirectly and is otherwise
  trivial getters.

Future CLs will include interpreter integration with minimal changes to
this Closure infrastructure.

Change-Id: I38a7aea8df1da7b154fd6623258c6c228c8e51df
diff --git a/runtime/lambda/closure_test.cc b/runtime/lambda/closure_test.cc
new file mode 100644
index 0000000..7c1bd0d
--- /dev/null
+++ b/runtime/lambda/closure_test.cc
@@ -0,0 +1,356 @@
+/*
+ * 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