Revert "Revert "lambda: Experimental support for capture-variable and liberate-variable""

This reverts commit 7bbb80ab52c203e44d2ded2c947b3b03b4b31ec4.

Change-Id: If806ce5c6c5e96fdb2c3761dee096f74e7e5b001
diff --git a/runtime/interpreter/interpreter_goto_table_impl.cc b/runtime/interpreter/interpreter_goto_table_impl.cc
index 72e2ba0..9677d79 100644
--- a/runtime/interpreter/interpreter_goto_table_impl.cc
+++ b/runtime/interpreter/interpreter_goto_table_impl.cc
@@ -17,9 +17,13 @@
 #if !defined(__clang__)
 // Clang 3.4 fails to build the goto interpreter implementation.
 
+
+#include "base/stl_util.h"  // MakeUnique
 #include "interpreter_common.h"
 #include "safe_math.h"
 
+#include <memory>  // std::unique_ptr
+
 namespace art {
 namespace interpreter {
 
@@ -179,6 +183,9 @@
     }
   }
 
+  std::unique_ptr<lambda::ClosureBuilder> lambda_closure_builder;
+  size_t lambda_captured_variable_index = 0;
+
   // Jump to first instruction.
   ADVANCE(0);
   UNREACHABLE_CODE_CHECK();
@@ -2412,7 +2419,20 @@
   HANDLE_INSTRUCTION_END();
 
   HANDLE_EXPERIMENTAL_INSTRUCTION_START(CREATE_LAMBDA) {
-    bool success = DoCreateLambda<true>(self, shadow_frame, inst);
+    if (lambda_closure_builder == nullptr) {
+      // DoCreateLambda always needs a ClosureBuilder, even if it has 0 captured variables.
+      lambda_closure_builder = MakeUnique<lambda::ClosureBuilder>();
+    }
+
+    // TODO: these allocations should not leak, and the lambda method should not be local.
+    lambda::Closure* lambda_closure =
+        reinterpret_cast<lambda::Closure*>(alloca(lambda_closure_builder->GetSize()));
+    bool success = DoCreateLambda<do_access_check>(self,
+                                                   inst,
+                                                   /*inout*/shadow_frame,
+                                                   /*inout*/lambda_closure_builder.get(),
+                                                   /*inout*/lambda_closure);
+    lambda_closure_builder.reset(nullptr);  // reset state of variables captured
     POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
   }
   HANDLE_EXPERIMENTAL_INSTRUCTION_END();
@@ -2429,6 +2449,31 @@
   }
   HANDLE_EXPERIMENTAL_INSTRUCTION_END();
 
+  HANDLE_EXPERIMENTAL_INSTRUCTION_START(CAPTURE_VARIABLE) {
+    if (lambda_closure_builder == nullptr) {
+      lambda_closure_builder = MakeUnique<lambda::ClosureBuilder>();
+    }
+
+    bool success = DoCaptureVariable<do_access_check>(self,
+                                                      inst,
+                                                      /*inout*/shadow_frame,
+                                                      /*inout*/lambda_closure_builder.get());
+
+    POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
+  }
+  HANDLE_EXPERIMENTAL_INSTRUCTION_END();
+
+  HANDLE_EXPERIMENTAL_INSTRUCTION_START(LIBERATE_VARIABLE) {
+    bool success = DoLiberateVariable<do_access_check>(self,
+                                                           inst,
+                                                           lambda_captured_variable_index,
+                                                           /*inout*/shadow_frame);
+    // Temporarily only allow sequences of 'liberate-variable, liberate-variable, ...'
+    lambda_captured_variable_index++;
+    POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
+  }
+  HANDLE_EXPERIMENTAL_INSTRUCTION_END();
+
   HANDLE_INSTRUCTION_START(UNUSED_3E)
     UnexpectedOpcode(inst, shadow_frame);
   HANDLE_INSTRUCTION_END();
@@ -2465,14 +2510,6 @@
     UnexpectedOpcode(inst, shadow_frame);
   HANDLE_INSTRUCTION_END();
 
-  HANDLE_INSTRUCTION_START(UNUSED_F5)
-    UnexpectedOpcode(inst, shadow_frame);
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(UNUSED_F7)
-    UnexpectedOpcode(inst, shadow_frame);
-  HANDLE_INSTRUCTION_END();
-
   HANDLE_INSTRUCTION_START(UNUSED_FA)
     UnexpectedOpcode(inst, shadow_frame);
   HANDLE_INSTRUCTION_END();