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/stack.cc b/runtime/stack.cc
index 9098d38..2ff9fd2 100644
--- a/runtime/stack.cc
+++ b/runtime/stack.cc
@@ -172,12 +172,23 @@
} else {
return cur_shadow_frame_->GetVRegReference(0);
}
- } else if (m->IsProxyMethod()) {
+ } else if (m->IsReflectProxyMethod()) {
if (cur_quick_frame_ != nullptr) {
return artQuickGetProxyThisObject(cur_quick_frame_);
} else {
return cur_shadow_frame_->GetVRegReference(0);
}
+ } else if (m->IsLambdaProxyMethod()) {
+ if (cur_quick_frame_ != nullptr) {
+ // XX: Should be safe to return null here, the lambda proxies
+ // don't set up their own quick frame because they don't need to spill any registers.
+ // By the time we are executing inside of the final target of the proxy invoke,
+ // the original 'this' reference is no longer live.
+ LOG(WARNING) << "Lambda proxies don't have a quick frame, do they?!";
+ return nullptr;
+ } else {
+ return cur_shadow_frame_->GetVRegReference(0);
+ }
} else {
const DexFile::CodeItem* code_item = m->GetCodeItem();
if (code_item == nullptr) {
@@ -814,7 +825,27 @@
// compiled method without any stubs. Therefore the method must have a OatQuickMethodHeader.
DCHECK(!method->IsDirect() && !method->IsConstructor())
<< "Constructors of proxy classes must have a OatQuickMethodHeader";
- return runtime->GetCalleeSaveMethodFrameInfo(Runtime::kRefsAndArgs);
+
+ if (method->IsReflectProxyMethod()) {
+ return runtime->GetCalleeSaveMethodFrameInfo(Runtime::kRefsAndArgs);
+ } else if (method->IsLambdaProxyMethod()) {
+ // Set this to true later once every stub works without a frame.
+ // This is currently 'false' because using a closure as a "long"
+ // requires a quick frame to be set up on 32-bit architectures.
+ constexpr bool kLambdaProxyStubsSupportFrameless = false;
+ if (kIsDebugBuild || !kLambdaProxyStubsSupportFrameless) {
+ // When debugging we always use the 'RefAndArgs' quick frame to allow us
+ // to see a runtime stub when unwinding.
+ return runtime->GetCalleeSaveMethodFrameInfo(Runtime::kRefsAndArgs);
+ } else {
+ // Lambda proxies don't bother setting up a quick frame for release builds.
+ LOG(FATAL) << "Requested QuickMethodFrameInfo for a lambda proxy,"
+ << "but it doesn't have one, for method: " << PrettyMethod(method);
+ UNREACHABLE();
+ }
+ } else {
+ LOG(FATAL) << "Unknown type of proxy method " << PrettyMethod(method);
+ }
}
// The only remaining case is if the method is native and uses the generic JNI stub.