lambda: Add support for invoke-interface for boxed innate lambdas
Lambda closures created with the 'create-lambda' instruction
(termed "innate lambdas") can be turned into an object with 'box-lambda'.
This CL enables support for those kinds of lambdas to work with
'invoke-interface' by generating a proxy class for the lambda.
Note: MIPS32/64 support not included.
Bug: 24618608
Bug: 25107649
Change-Id: Ic8f1bb66ebeaed4097e758a50becf1cff6ccaefb
diff --git a/runtime/interpreter/interpreter_common.h b/runtime/interpreter/interpreter_common.h
index 9f6699f..2de8e7e 100644
--- a/runtime/interpreter/interpreter_common.h
+++ b/runtime/interpreter/interpreter_common.h
@@ -888,12 +888,56 @@
return false;
}
+ StackHandleScope<1> hs{self}; // NOLINT: [readability/braces] [4];
+
+ // Use the lambda method's class loader since it's close enough.
+ // TODO: create-lambda should capture the current method's class loader and use that instead.
+ // TODO: Do we want create-lambda to work for static methods outside of the declaring class?
+ // --> then we need to store a classloader in the lambda method. otherwise we don't
+ // because it would always use the declaring class's class loader.
+ // TODO: add a GetClassLoader to the lambda closure which knows how to do this,
+ // don't hardcode this here.
+ Handle<ClassLoader> current_class_loader = hs.NewHandle(
+ lambda_closure->GetTargetMethod()->GetDeclaringClass()->GetClassLoader());
+
+ // TODO: get the type ID from the instruction
+ std::string class_name;
+ {
+ // Temporary hack to read the interface corresponding to a box-lambda.
+ // TODO: The box-lambda should encode the type ID instead, so we don't need to do this.
+ {
+ // Do a hack where we read from const-string the interface name
+ mirror::Object* string_reference = shadow_frame.GetVRegReference(vreg_target_object);
+
+ CHECK(string_reference != nullptr)
+ << "box-lambda needs the type name stored in string vA (target), but it was null";
+
+ CHECK(string_reference->IsString())
+ << "box-lambda needs the type name stored in string vA (target)";
+
+ mirror::String* as_string = string_reference->AsString();
+ class_name = as_string->ToModifiedUtf8();
+ }
+
+ // Trigger class loading of the functional interface.
+ // TODO: This should actually be done by the create-lambda...
+ if (Runtime::Current()->GetClassLinker()
+ ->FindClass(self, class_name.c_str(), current_class_loader) == nullptr) {
+ CHECK(self->IsExceptionPending());
+ self->AssertPendingException();
+ return false;
+ }
+ }
+
mirror::Object* closure_as_object =
- Runtime::Current()->GetLambdaBoxTable()->BoxLambda(lambda_closure);
+ Runtime::Current()->GetLambdaBoxTable()->BoxLambda(lambda_closure,
+ class_name.c_str(),
+ current_class_loader.Get());
// Failed to box the lambda, an exception was raised.
if (UNLIKELY(closure_as_object == nullptr)) {
CHECK(self->IsExceptionPending());
+ shadow_frame.SetVRegReference(vreg_target_object, nullptr);
return false;
}