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/art_lambda_method.h b/runtime/lambda/art_lambda_method.h
new file mode 100644
index 0000000..892d8c6
--- /dev/null
+++ b/runtime/lambda/art_lambda_method.h
@@ -0,0 +1,116 @@
+/*
+ * 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.
+ */
+#ifndef ART_RUNTIME_LAMBDA_ART_LAMBDA_METHOD_H_
+#define ART_RUNTIME_LAMBDA_ART_LAMBDA_METHOD_H_
+
+#include "base/macros.h"
+#include "art_method.h"
+
+#include <stdint.h>
+
+namespace art {
+namespace lambda {
+
+class ArtLambdaMethod {
+ public:
+ // Construct an art lambda method.
+ // The target method is the one invoked by invoke-lambda.
+ // The type descriptor describes the types of variables captured, e.g. "ZFLObject;\FI;[Z"
+ // The shorty drops the object name and treats arrays as objects, e.g. "ZFL\L"
+ // Innate lambda means that the lambda was originally created via invoke-lambda.
+ // -- Non-innate lambdas (learned lambdas) come from a regular class that was boxed to lambda.
+ // (Ownership of strings is retained by the caller and the lifetime should exceed this class).
+ ArtLambdaMethod(ArtMethod* target_method,
+ const char* captured_variables_type_descriptor,
+ const char* captured_variables_shorty_,
+ bool innate_lambda = true);
+
+ // Get the target method for this lambda that would be used by the invoke-lambda dex instruction.
+ ArtMethod* GetArtMethod() const {
+ return method_;
+ }
+
+ // Get the compile-time size of lambda closures for this method in bytes.
+ // This is circular (that is, it includes the size of the ArtLambdaMethod pointer).
+ // One should also check if the size is dynamic since nested lambdas have a runtime size.
+ size_t GetStaticClosureSize() const {
+ return closure_size_;
+ }
+
+ // Get the type descriptor for the list of captured variables.
+ // e.g. "ZFLObject;\FI;[Z" means a captured int, float, class Object, lambda FI, array of ints
+ const char* GetCapturedVariablesTypeDescriptor() const {
+ return captured_variables_type_descriptor_;
+ }
+
+ // Get the shorty 'field' type descriptor list of captured variables.
+ // This follows the same rules as a string of ShortyFieldType in the dex specification.
+ // Every captured variable is represented by exactly one character.
+ // - Objects become 'L'.
+ // - Arrays become 'L'.
+ // - Lambdas become '\'.
+ const char* GetCapturedVariablesShortyTypeDescriptor() const {
+ return captured_variables_shorty_;
+ }
+
+ // Will the size of this lambda change at runtime?
+ // Only returns true if there is a nested lambda that we can't determine statically the size of.
+ bool IsDynamicSize() const {
+ return dynamic_size_;
+ }
+
+ // Will the size of this lambda always be constant at runtime?
+ // This generally means there's no nested lambdas, or we were able to successfully determine
+ // their size statically at compile time.
+ bool IsStaticSize() const {
+ return !IsDynamicSize();
+ }
+ // Is this a lambda that was originally created via invoke-lambda?
+ // -- Non-innate lambdas (learned lambdas) come from a regular class that was boxed to lambda.
+ bool IsInnateLambda() const {
+ return innate_lambda_;
+ }
+
+ // How many variables were captured?
+ // (Each nested lambda counts as 1 captured var regardless of how many captures it itself has).
+ size_t GetNumberOfCapturedVariables() const {
+ return strlen(captured_variables_shorty_);
+ }
+
+ private:
+ // TODO: ArtMethod, or at least the entry points should be inlined into this struct
+ // to avoid an extra indirect load when doing invokes.
+ // Target method that invoke-lambda will jump to.
+ ArtMethod* method_;
+ // How big the closure is (in bytes). Only includes the constant size.
+ size_t closure_size_;
+ // The type descriptor for the captured variables, e.g. "IS" for [int, short]
+ const char* captured_variables_type_descriptor_;
+ // The shorty type descriptor for captured vars, (e.g. using 'L' instead of 'LObject;')
+ const char* captured_variables_shorty_;
+ // Whether or not the size is dynamic. If it is, copiers need to read the Closure size at runtime.
+ bool dynamic_size_;
+ // True if this lambda was originally made with create-lambda,
+ // false if it came from a class instance (through new-instance and then unbox-lambda).
+ bool innate_lambda_;
+
+ DISALLOW_COPY_AND_ASSIGN(ArtLambdaMethod);
+};
+
+} // namespace lambda
+} // namespace art
+
+#endif // ART_RUNTIME_LAMBDA_ART_LAMBDA_METHOD_H_