Revert "lambda: Add support for invoke-interface for boxed innate lambdas"
955-lambda is flaky
Bug: 24618608
Bug: 25107649
This reverts commit 457e874459ae638145cab6d572e34d48480e39d2.
Change-Id: I24884344d21d7a4262e53e3f5dba57032687ddb7
diff --git a/runtime/Android.mk b/runtime/Android.mk
index 4f4792a..0b0f094 100644
--- a/runtime/Android.mk
+++ b/runtime/Android.mk
@@ -106,7 +106,6 @@
jit/profiling_info.cc \
lambda/art_lambda_method.cc \
lambda/box_table.cc \
- lambda/box_class_table.cc \
lambda/closure.cc \
lambda/closure_builder.cc \
lambda/leaking_allocator.cc \
diff --git a/runtime/arch/arch_test.cc b/runtime/arch/arch_test.cc
index 771c8b7..d6ba304 100644
--- a/runtime/arch/arch_test.cc
+++ b/runtime/arch/arch_test.cc
@@ -46,15 +46,9 @@
}
};
-} // namespace art
-
// Common tests are declared next to the constants.
#define ADD_TEST_EQ(x, y) EXPECT_EQ(x, y);
#include "asm_support.h"
-// Important: Do not include this inside of another namespace, since asm_support.h
-// defines its own namespace which must not be nested.
-
-namespace art {
TEST_F(ArchTest, CheckCommonOffsetsAndSizes) {
CheckAsmSupportOffsetsAndSizes();
diff --git a/runtime/arch/arm/quick_entrypoints_arm.S b/runtime/arch/arm/quick_entrypoints_arm.S
index 588268d..631b784 100644
--- a/runtime/arch/arm/quick_entrypoints_arm.S
+++ b/runtime/arch/arm/quick_entrypoints_arm.S
@@ -1045,26 +1045,6 @@
DELIVER_PENDING_EXCEPTION
END art_quick_proxy_invoke_handler
-// Forward call from boxed innate lambda to the underlying lambda closure's target method.
- .extern artQuickLambdaProxyInvokeHandler
-ENTRY art_quick_lambda_proxy_invoke_handler
-// TODO: have a faster handler that doesn't need to set up a frame
- SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME_WITH_METHOD_IN_R0
- mov r2, r9 @ pass Thread::Current
- mov r3, sp @ pass SP
- blx artQuickLambdaProxyInvokeHandler @ (Method* proxy method, receiver, Thread*, SP)
- ldr r2, [r9, #THREAD_EXCEPTION_OFFSET] @ load Thread::Current()->exception_
- // Tear down the callee-save frame. Skip arg registers.
- add sp, #(FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE - FRAME_SIZE_REFS_ONLY_CALLEE_SAVE)
- .cfi_adjust_cfa_offset -(FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE - FRAME_SIZE_REFS_ONLY_CALLEE_SAVE)
- RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME
- cbnz r2, 1f @ success if no exception is pending
- vmov d0, r0, r1 @ store into fpr, for when it's a fpr return...
- bx lr @ return on success
-1:
- DELIVER_PENDING_EXCEPTION
-END art_quick_lambda_proxy_invoke_handler
-
/*
* Called to resolve an imt conflict. r12 is a hidden argument that holds the target method's
* dex method index.
diff --git a/runtime/arch/arm64/quick_entrypoints_arm64.S b/runtime/arch/arm64/quick_entrypoints_arm64.S
index 177873d..9ccabad 100644
--- a/runtime/arch/arm64/quick_entrypoints_arm64.S
+++ b/runtime/arch/arm64/quick_entrypoints_arm64.S
@@ -1582,28 +1582,6 @@
DELIVER_PENDING_EXCEPTION
END art_quick_proxy_invoke_handler
- /*
- * Called by managed code that is attempting to call a method on a lambda proxy class. On entry
- * x0 holds the lambda proxy method and x1 holds the receiver; The frame size of the invoked
- * lambda proxy method agrees with a ref and args callee save frame.
- */
- .extern artQuickLambdaProxyInvokeHandler
-ENTRY art_quick_lambda_proxy_invoke_handler
-// TODO: have a faster way to invoke lambda proxies without setting up the whole frame.
- SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME_WITH_METHOD_IN_X0
- mov x2, xSELF // pass Thread::Current
- mov x3, sp // pass SP
- bl artQuickLambdaProxyInvokeHandler // (Method* proxy method, receiver, Thread*, SP)
- ldr x2, [xSELF, THREAD_EXCEPTION_OFFSET]
- cbnz x2, .Lexception_in_lambda_proxy // success if no exception is pending
- RESTORE_REFS_AND_ARGS_CALLEE_SAVE_FRAME // Restore frame
- fmov d0, x0 // Store result in d0 in case it was float or double
- ret // return on success
-.Lexception_in_lambda_proxy:
- RESTORE_REFS_AND_ARGS_CALLEE_SAVE_FRAME
- DELIVER_PENDING_EXCEPTION
-END art_quick_lambda_proxy_invoke_handler
-
/*
* Called to resolve an imt conflict. xIP1 is a hidden argument that holds the target method's
* dex method index.
diff --git a/runtime/arch/mips/quick_entrypoints_mips.S b/runtime/arch/mips/quick_entrypoints_mips.S
index af79f5e..0691f2a 100644
--- a/runtime/arch/mips/quick_entrypoints_mips.S
+++ b/runtime/arch/mips/quick_entrypoints_mips.S
@@ -1377,10 +1377,6 @@
DELIVER_PENDING_EXCEPTION
END art_quick_proxy_invoke_handler
-// Forward call from boxed innate lambda to the underlying lambda closure's target method.
- .extern artQuickLambdaProxyInvokeHandler
-UNIMPLEMENTED art_quick_lambda_proxy_invoke_handler
-
/*
* Called to resolve an imt conflict. t0 is a hidden argument that holds the target method's
* dex method index.
diff --git a/runtime/arch/mips64/quick_entrypoints_mips64.S b/runtime/arch/mips64/quick_entrypoints_mips64.S
index 5e70a95..66c8aad 100644
--- a/runtime/arch/mips64/quick_entrypoints_mips64.S
+++ b/runtime/arch/mips64/quick_entrypoints_mips64.S
@@ -1431,10 +1431,6 @@
DELIVER_PENDING_EXCEPTION
END art_quick_proxy_invoke_handler
-// Forward call from boxed innate lambda to the underlying lambda closure's target method.
- .extern artQuickLambdaProxyInvokeHandler
-UNIMPLEMENTED art_quick_lambda_proxy_invoke_handler
-
/*
* Called to resolve an imt conflict. t0 is a hidden argument that holds the target method's
* dex method index.
diff --git a/runtime/arch/x86/quick_entrypoints_x86.S b/runtime/arch/x86/quick_entrypoints_x86.S
index 4fb6119..463c9cf 100644
--- a/runtime/arch/x86/quick_entrypoints_x86.S
+++ b/runtime/arch/x86/quick_entrypoints_x86.S
@@ -1391,149 +1391,6 @@
RETURN_OR_DELIVER_PENDING_EXCEPTION // return or deliver exception
END_FUNCTION art_quick_proxy_invoke_handler
-#if LAMBDA_INVOKE_USES_LONG
-#undef LAMBDA_PROXY_SETUP_FRAME
-// We need to always do a 'pop' to readjust the stack, so we have to use the slower call instruction.
-#define LAMBDA_PROXY_SETUP_FRAME 1
-#define LAMBDA_INVOKE_REALIGN_STACK_FRAME 1
-#else
-#define LAMBDA_INVOKE_REALIGN_STACK_FRAME 0
-#endif
-
-#define LAMBDA_INVOKE_CALLS_INTO_RUNTIME LAMBDA_INVOKE_REALIGN_STACK_FRAME
-
-// Forward call from boxed innate lambda to the underlying lambda closure's target method.
-DEFINE_FUNCTION art_quick_lambda_proxy_invoke_handler
- // This function is always called when the lambda is innate.
- // Therefore we can assume the box is to an innate lambda.
- // TODO: perhaps there should be a DCHECK to make sure it's innate?
-
-#if LAMBDA_PROXY_SETUP_FRAME
- // Set up a quick frame when debugging so we can see that it's going through a stub.
- // An invoke-virtual + a stub invocation is enough of a hint that we *could* be
- // going through a lambda proxy.
- SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME_WITH_METHOD_IN_EAX
-#endif
-
-#if !LAMBDA_INVOKE_CALLS_INTO_RUNTIME
- // Rewrite the following 2 arguments, stored on stack frame:
- //
- // |--------|
- // |receiver| <- esp-4
- // |--------|
- // | method | <- esp
- // |--------|
-
- // Set up the new correct method receiver (swap object with closure).
- // -- The original object is no longer available after this.
- //
- // (Before)
- // ecx == mirror::Object* boxed_lambda; // lambda proxy object.
- movl MIRROR_OBJECT_BOXED_INNATE_LAMBDA_CLOSURE_POINTER_OFFSET(%ecx), %ecx
- // (After)
- // lambda::Closure* closure = boxed_lambda->closure_;
- // boxed_lambda = closure; // Overwrite lambda proxy object
- // ecx == closure
-
- // Look up the new correct method target.
- // -- The original method target is no longer available after this.
- //
- // (Before)
- // eax == ArtMethod* old_receiver_method;
- movl LAMBDA_CLOSURE_METHOD_OFFSET(%ecx), %eax
- // (After)
- // ArtLambdaMethod* lambda_method_target = closure->lambda_info_;
- // eax = lambda_method_target
- //
- // Set up the correct method target from the lambda info.
- movl ART_LAMBDA_METHOD_ART_METHOD_OFFSET(%eax), %eax // Load new receiver method
- // (After)
- // ArtMethod* target_method = lambda_method_target->target_
- // eax = target_method
-#endif
-
-#if LAMBDA_INVOKE_CALLS_INTO_RUNTIME
- PUSH esp // pass SP
- pushl %fs:THREAD_SELF_OFFSET // pass Thread::Current()
- CFI_ADJUST_CFA_OFFSET(4)
- PUSH ecx // pass receiver
- PUSH eax // pass proxy method
- call SYMBOL(artQuickLambdaProxyInvokeHandler) // (proxy method, receiver, Thread*, SP)
- movd %eax, %xmm0 // place return value also into floating point return value
- movd %edx, %xmm1
- punpckldq %xmm1, %xmm0
- addl LITERAL(16 + FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE - FRAME_SIZE_REFS_ONLY_CALLEE_SAVE), %esp
- CFI_ADJUST_CFA_OFFSET(-(16 + FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE - FRAME_SIZE_REFS_ONLY_CALLEE_SAVE))
- RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME
- RETURN_OR_DELIVER_PENDING_EXCEPTION // return or deliver exception
-#endif
-
-#if LAMBDA_INVOKE_USES_LONG && !LAMBDA_INVOKE_REALIGN_STACK_FRAME
- // As a temporary workaround, lambda functions look like
- // (J[Arg2][Arg3][Arg4]...)
- // This means that we can't just pass in the lambda as a 32-bit pointer
- // We pad the arguments with an extra 32-bit "0" where Arg2 used to be instead.
-
- // Required arguments for a lambda method:
- //
- // Arg0 = eax = method
- // Arg1 = ecx = closure (hi)
- // Arg2 = edx = closure (lo)
- // Arg3 = ebx = <?> (first user-defined argument)
-
- // Transformation diagram:
- //
- // Arg0 Arg1 Arg2 Arg3 ... ArgN
- // | | \ \ \
- // | | \ \ \
- // Arg0 Arg1 0x00 Arg2 Arg3 ... ArgN
- // /\
- // (inserted)
- PUSH ebx // Move out Arg3 into Arg4, and also for all K>3 ArgK into ArgK+1
- mov %edx, %ebx // Move out Arg2 into Arg3
- xor %edx, %edx // Clear closure 32-bit low register
-
- // XX: Does this work at all ? This probably breaks the visitors (*and* its unaligned).
-
- // FIXME: call into the runtime and do a proxy-like-invoke
- // using a ShadowFrame quick visitor, and then use ArtMethod::Invoke
- // to call into the actual method (which will take care of fixing up alignment).
- // Trying to realign in the assembly itself won't actually work
- // since then the visitor will unwind incorrectly (unless we also fixed up the ManagedStack).
-#endif
-
- // TODO: avoid extra indirect load by subclass ArtLambdaMethod from ArtMethod.
-
- // Forward the call to the overwritten receiver method.
- // -- Arguments [2,N] are left completely untouched since the signature is otherwise identical.
-#if LAMBDA_PROXY_SETUP_FRAME
- #if LAMBDA_INVOKE_CALLS_INTO_RUNTIME
- // Have to call into runtime in order to re-align the stack frame to 16 bytes.
- int3
- #else
- // Just call into the method directly. Don't worry about realigning.
- call *ART_METHOD_QUICK_CODE_OFFSET_32(%eax) // (new method, new receiver, old args...)
-
- // The stack frame was manually adjusted, so make sure we have a pop here to fix it back.
- #if LAMBDA_INVOKE_USES_LONG && !LAMBDA_INVOKE_REALIGN_STACK_FRAME
-
- POP ecx // OK: ecx is scratch register after the call.
- // XX: use 'add esp, 4' instead if we need to keep the register? This way we get cleaner CFI.
- #endif
- #endif
- RESTORE_REFS_ONLY_CALLEE_SAVE_FRAME
-
-#else
- // Do not use 'call' here since the stack visitors wouldn't know how to visit this frame.
- jmp *ART_METHOD_QUICK_CODE_OFFSET_32(%eax) // tailcall (new method, new receiver, old args...)
-#endif
-
-#if LAMBDA_PROXY_SETUP_FRAME
- ret
-#endif
-
-END_FUNCTION art_quick_lambda_proxy_invoke_handler
-
/*
* Called to resolve an imt conflict. xmm7 is a hidden argument that holds the target method's
* dex method index.
diff --git a/runtime/arch/x86_64/quick_entrypoints_x86_64.S b/runtime/arch/x86_64/quick_entrypoints_x86_64.S
index 0a54aa3..17d277e 100644
--- a/runtime/arch/x86_64/quick_entrypoints_x86_64.S
+++ b/runtime/arch/x86_64/quick_entrypoints_x86_64.S
@@ -1297,6 +1297,7 @@
RETURN_IF_EAX_ZERO // return or deliver exception
END_FUNCTION art_quick_set64_static
+
DEFINE_FUNCTION art_quick_proxy_invoke_handler
SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME_WITH_METHOD_IN_RDI
@@ -1308,60 +1309,6 @@
RETURN_OR_DELIVER_PENDING_EXCEPTION
END_FUNCTION art_quick_proxy_invoke_handler
-// Forward call from boxed innate lambda to the underlying lambda closure's target method.
-DEFINE_FUNCTION art_quick_lambda_proxy_invoke_handler
- // This function is always called when the lambda is innate.
- // Therefore we can assume the box is to an innate lambda.
- // TODO: perhaps there should be a DCHECK to make sure it's innate?
-
-#if LAMBDA_PROXY_SETUP_FRAME
- // Set up a quick frame when debugging so we can see that it's going through a stub.
- // Our stack traces will contain the quick lambda proxy hander.
- // Note that we *must* go through the handler (when spilling) otherwise we won't know how
- // to move the spilled GC references from the caller to this stub.
- SETUP_REFS_AND_ARGS_CALLEE_SAVE_FRAME_WITH_METHOD_IN_RDI
-
- movq %gs:THREAD_SELF_OFFSET, %rdx // Pass Thread::Current().
- movq %rsp, %rcx // Pass SP.
- call SYMBOL(artQuickLambdaProxyInvokeHandler) // (proxy method, receiver, Thread*, SP)
- RESTORE_REFS_AND_ARGS_CALLEE_SAVE_FRAME
- movq %rax, %xmm0 // Copy return value in case of float returns.
- RETURN_OR_DELIVER_PENDING_EXCEPTION
-#else
- // Set up the new correct method receiver (swap object with closure).
- // -- The original object is no longer available after this.
- //
- // (Before)
- // rsi == mirror::Object* boxed_lambda; // lambda proxy object.
- movq MIRROR_OBJECT_BOXED_INNATE_LAMBDA_CLOSURE_POINTER_OFFSET(%rsi), %rsi
- // (After)
- // lambda::Closure* closure = boxed_lambda->closure_; // Overwrite receiver object.
- // rsi == closure
-
- // Look up the new correct method target.
- // -- The original method target is no longer available after this.
- movq LAMBDA_CLOSURE_METHOD_OFFSET(%rsi), %rdi // Overwrite old receiver method.
- // (After)
- // ArtLambdaMethod* lambda_method_target = closure->lambda_info_;
- // rdi == lambda_method_target
-
- // TODO: avoid extra indirect load by subclass ArtLambdaMethod from ArtMethod.
-
- // Set up the correct method target from the lambda info.
- movq ART_LAMBDA_METHOD_ART_METHOD_OFFSET(%rdi), %rdi // Write new receiver method.
- // (After)
- // ArtMethod* method_target = lambda_method_target->target_;
- // rdi == method_target
-
- // Forward the call to the overwritten receiver method.
- // -- Arguments [2,N] are left completely untouched since the signature is otherwise identical.
- // Do not use 'call' here since the stack would be misaligned (8b instead of 16b).
- // Also the stack visitors wouldn't know how to visit this frame if we used a call.
- jmp *ART_METHOD_QUICK_CODE_OFFSET_64(%rdi) // tailcall (new method, new receiver, old args...)
-#endif
-
-END_FUNCTION art_quick_lambda_proxy_invoke_handler
-
/*
* Called to resolve an imt conflict.
* rax is a hidden argument that holds the target method's dex method index.
diff --git a/runtime/art_field-inl.h b/runtime/art_field-inl.h
index ab42d0e..4166e22 100644
--- a/runtime/art_field-inl.h
+++ b/runtime/art_field-inl.h
@@ -255,7 +255,7 @@
inline const char* ArtField::GetName() SHARED_REQUIRES(Locks::mutator_lock_) {
uint32_t field_index = GetDexFieldIndex();
- if (UNLIKELY(GetDeclaringClass()->IsAnyProxyClass())) {
+ if (UNLIKELY(GetDeclaringClass()->IsProxyClass())) {
DCHECK(IsStatic());
DCHECK_LT(field_index, 2U);
return field_index == 0 ? "interfaces" : "throws";
@@ -266,7 +266,7 @@
inline const char* ArtField::GetTypeDescriptor() SHARED_REQUIRES(Locks::mutator_lock_) {
uint32_t field_index = GetDexFieldIndex();
- if (UNLIKELY(GetDeclaringClass()->IsAnyProxyClass())) {
+ if (UNLIKELY(GetDeclaringClass()->IsProxyClass())) {
DCHECK(IsStatic());
DCHECK_LT(field_index, 2U);
// 0 == Class[] interfaces; 1 == Class[][] throws;
@@ -290,8 +290,8 @@
inline mirror::Class* ArtField::GetType() {
const uint32_t field_index = GetDexFieldIndex();
auto* declaring_class = GetDeclaringClass();
- if (UNLIKELY(declaring_class->IsAnyProxyClass())) {
- return AnyProxyFindSystemClass(GetTypeDescriptor());
+ if (UNLIKELY(declaring_class->IsProxyClass())) {
+ return ProxyFindSystemClass(GetTypeDescriptor());
}
auto* dex_cache = declaring_class->GetDexCache();
const DexFile* const dex_file = dex_cache->GetDexFile();
diff --git a/runtime/art_field.cc b/runtime/art_field.cc
index 3ac563a..3737e0d 100644
--- a/runtime/art_field.cc
+++ b/runtime/art_field.cc
@@ -69,8 +69,8 @@
return nullptr;
}
-mirror::Class* ArtField::AnyProxyFindSystemClass(const char* descriptor) {
- DCHECK(GetDeclaringClass()->IsAnyProxyClass());
+mirror::Class* ArtField::ProxyFindSystemClass(const char* descriptor) {
+ DCHECK(GetDeclaringClass()->IsProxyClass());
return Runtime::Current()->GetClassLinker()->FindSystemClass(Thread::Current(), descriptor);
}
diff --git a/runtime/art_field.h b/runtime/art_field.h
index 4ebe6fb..a943a34 100644
--- a/runtime/art_field.h
+++ b/runtime/art_field.h
@@ -191,9 +191,7 @@
}
private:
- mirror::Class* AnyProxyFindSystemClass(const char* descriptor)
- SHARED_REQUIRES(Locks::mutator_lock_);
- mirror::Class* LambdaProxyFindSystemClass(const char* descriptor)
+ mirror::Class* ProxyFindSystemClass(const char* descriptor)
SHARED_REQUIRES(Locks::mutator_lock_);
mirror::Class* ResolveGetType(uint32_t type_idx) SHARED_REQUIRES(Locks::mutator_lock_);
mirror::String* ResolveGetStringName(Thread* self, const DexFile& dex_file, uint32_t string_idx,
diff --git a/runtime/art_method-inl.h b/runtime/art_method-inl.h
index b6e811f..cf548ad 100644
--- a/runtime/art_method-inl.h
+++ b/runtime/art_method-inl.h
@@ -292,7 +292,7 @@
}
inline const char* ArtMethod::GetShorty(uint32_t* out_length) {
- DCHECK(!IsProxyMethod() || IsLambdaProxyMethod()); // OK: lambda proxies use parent dex cache.
+ DCHECK(!IsProxyMethod());
const DexFile* dex_file = GetDexFile();
return dex_file->GetMethodShorty(dex_file->GetMethodId(GetDexMethodIndex()), out_length);
}
@@ -354,31 +354,10 @@
}
inline const DexFile::TypeList* ArtMethod::GetParameterTypeList() {
- // XX: Do proxy methods have a dex file? not sure.
+ DCHECK(!IsProxyMethod());
const DexFile* dex_file = GetDexFile();
- const DexFile::MethodId* method_id = nullptr;
-
- if (kIsDebugBuild) {
- if (UNLIKELY(IsProxyMethod())) {
- // Proxy method case.
- CHECK(IsLambdaProxyMethod()) << "Cannot GetParameterTypeList for java.lang.reflect.Proxy";
-
- //
- // We do not have a method ID, so look up one of the supers we overrode,
- // it will have the same exact parameter type list as we do.
-
- // Lambda proxy classes have the dex cache from their single interface parent.
- // Proxy classes have multiple interface parents, so they use the root dexcache instead.
- //
- // For lambda proxy classes only, get the type list data from the parent.
- // (code happens to look the same as the usual non-proxy path).
- }
- }
-
- method_id = &dex_file->GetMethodId(GetDexMethodIndex());
- DCHECK(method_id != nullptr);
-
- const DexFile::ProtoId& proto = dex_file->GetMethodPrototype(*method_id);
+ const DexFile::ProtoId& proto = dex_file->GetMethodPrototype(
+ dex_file->GetMethodId(GetDexMethodIndex()));
return dex_file->GetProtoParameters(proto);
}
@@ -418,20 +397,12 @@
}
inline mirror::DexCache* ArtMethod::GetDexCache() {
- DCHECK(!IsProxyMethod() || IsLambdaProxyMethod()); // OK: lambda proxies use parent dex cache.
+ DCHECK(!IsProxyMethod());
return GetDeclaringClass()->GetDexCache();
}
inline bool ArtMethod::IsProxyMethod() {
- return GetDeclaringClass()->IsAnyProxyClass();
-}
-
-inline bool ArtMethod::IsReflectProxyMethod() {
- return GetDeclaringClass()->IsReflectProxyClass();
-}
-
-inline bool ArtMethod::IsLambdaProxyMethod() {
- return GetDeclaringClass()->IsLambdaProxyClass();
+ return GetDeclaringClass()->IsProxyClass();
}
inline ArtMethod* ArtMethod::GetInterfaceMethodIfProxy(size_t pointer_size) {
@@ -477,9 +448,9 @@
void ArtMethod::VisitRoots(RootVisitorType& visitor, size_t pointer_size) {
ArtMethod* interface_method = nullptr;
mirror::Class* klass = declaring_class_.Read();
- if (UNLIKELY(klass != nullptr && klass->IsAnyProxyClass())) {
+ if (UNLIKELY(klass != nullptr && klass->IsProxyClass())) {
// For normal methods, dex cache shortcuts will be visited through the declaring class.
- // However, for any proxies we need to keep the interface method alive, so we visit its roots.
+ // However, for proxies we need to keep the interface method alive, so we visit its roots.
interface_method = mirror::DexCache::GetElementPtrSize(
GetDexCacheResolvedMethods(pointer_size),
GetDexMethodIndex(),
diff --git a/runtime/art_method.h b/runtime/art_method.h
index 98f5aee..5a2d6c3 100644
--- a/runtime/art_method.h
+++ b/runtime/art_method.h
@@ -171,16 +171,8 @@
return (GetAccessFlags() & kAccSynthetic) != 0;
}
- // Does this method live on a declaring class that is itself any proxy class?
- // -- Returns true for both java.lang.reflect.Proxy and java.lang.LambdaProxy subclasses.
bool IsProxyMethod() SHARED_REQUIRES(Locks::mutator_lock_);
- // Does this method live in a java.lang.reflect.Proxy subclass?
- bool IsReflectProxyMethod() SHARED_REQUIRES(Locks::mutator_lock_);
-
- // Does this method live in a java.lang.LambdaProxy subclass?
- bool IsLambdaProxyMethod() SHARED_REQUIRES(Locks::mutator_lock_);
-
bool IsPreverified() {
return (GetAccessFlags() & kAccPreverified) != 0;
}
@@ -282,15 +274,7 @@
uint32_t name_and_signature_idx)
SHARED_REQUIRES(Locks::mutator_lock_);
- // Invoke this method, passing all the virtual registers in args.
- // -- args_size must be the size in bytes (not size in words)!
- // -- shorty must be the method shorty (i.e. it includes the return type).
- // The result is set when the method finishes execution successfully.
- void Invoke(Thread* self,
- uint32_t* args,
- uint32_t args_size, // NOTE: size in bytes
- /*out*/JValue* result,
- const char* shorty)
+ void Invoke(Thread* self, uint32_t* args, uint32_t args_size, JValue* result, const char* shorty)
SHARED_REQUIRES(Locks::mutator_lock_);
const void* GetEntryPointFromQuickCompiledCode() {
@@ -444,9 +428,6 @@
mirror::DexCache* GetDexCache() SHARED_REQUIRES(Locks::mutator_lock_);
- // Returns the current method ('this') if this is a regular, non-proxy method.
- // Otherwise, when this class is a proxy (IsProxyMethod), look-up the original interface's
- // method (that the proxy is "overriding") and return that.
ALWAYS_INLINE ArtMethod* GetInterfaceMethodIfProxy(size_t pointer_size)
SHARED_REQUIRES(Locks::mutator_lock_);
diff --git a/runtime/asm_support.h b/runtime/asm_support.h
index 785a9be..b548dfb 100644
--- a/runtime/asm_support.h
+++ b/runtime/asm_support.h
@@ -19,12 +19,9 @@
#if defined(__cplusplus)
#include "art_method.h"
-#include "lambda/art_lambda_method.h"
-#include "lambda/closure.h"
#include "gc/allocator/rosalloc.h"
#include "lock_word.h"
#include "mirror/class.h"
-#include "mirror/lambda_proxy.h"
#include "mirror/string.h"
#include "runtime.h"
#include "thread.h"
@@ -52,8 +49,6 @@
#define ADD_TEST_EQ(x, y) CHECK_EQ(x, y);
#endif
-namespace art {
-
static inline void CheckAsmSupportOffsetsAndSizes() {
#else
#define ADD_TEST_EQ(x, y)
@@ -303,80 +298,9 @@
static_cast<int32_t>(art::gc::allocator::RosAlloc::RunSlotNextOffset()))
// Assert this so that we can avoid zeroing the next field by installing the class pointer.
ADD_TEST_EQ(ROSALLOC_SLOT_NEXT_OFFSET, MIRROR_OBJECT_CLASS_OFFSET)
-// Working with raw lambdas (lambda::Closure) in raw memory:
-//
-// |---------------------|
-// | ArtLambdaMethod* | <-- pointer to lambda art method, has the info like the size.
-// |---------------------| <-- 'data offset'
-// | [ Dynamic Size ] | <-- OPTIONAL: only if the ArtLambdaMethod::dynamic_size_ is true.
-// |---------------------|
-// | Captured Variables |
-// | ... |
-// |---------------------| <-- total length determined by "dynamic size" if it is present,
-// otherwise by the ArtLambdaMethod::static_size_
-
-// Offset from start of lambda::Closure to the ArtLambdaMethod*.
-#define LAMBDA_CLOSURE_METHOD_OFFSET 0
-ADD_TEST_EQ(static_cast<size_t>(LAMBDA_CLOSURE_METHOD_OFFSET),
- offsetof(art::lambda::ClosureStorage, lambda_info_))
-// Offset from the start of lambda::Closure to the data (captured vars or dynamic size).
-#define LAMBDA_CLOSURE_DATA_OFFSET __SIZEOF_POINTER__
-ADD_TEST_EQ(static_cast<size_t>(LAMBDA_CLOSURE_DATA_OFFSET),
- offsetof(art::lambda::ClosureStorage, captured_))
-// Offsets to captured variables intentionally omitted as it needs a runtime branch.
-
-// The size of a lambda closure after it's been compressed down for storage.
-// -- Although a lambda closure is a virtual register pair (64-bit), we only need 32-bit
-// to track the pointer when we are on 32-bit architectures.
-// Both the compiler and the runtime therefore compress the closure down for 32-bit archs.
-#define LAMBDA_CLOSURE_COMPRESSED_POINTER_SIZE __SIZEOF_POINTER__
-ADD_TEST_EQ(static_cast<size_t>(LAMBDA_CLOSURE_COMPRESSED_POINTER_SIZE),
- sizeof(art::lambda::Closure*))
-
-// Working with boxed innate lambdas (as a mirror::Object) in raw memory:
-// --- Note that this layout only applies to lambdas originally made with create-lambda.
-// --- Boxing a lambda created from a new-instance instruction is simply the original object.
-//
-// |---------------------|
-// | object header |
-// |---------------------|
-// | lambda::Closure* | <-- long on 64-bit, int on 32-bit
-// |---------------------|
-#define MIRROR_OBJECT_BOXED_INNATE_LAMBDA_CLOSURE_POINTER_OFFSET (MIRROR_OBJECT_HEADER_SIZE)
-ADD_TEST_EQ(static_cast<size_t>(MIRROR_OBJECT_BOXED_INNATE_LAMBDA_CLOSURE_POINTER_OFFSET),
- art::mirror::LambdaProxy::GetInstanceFieldOffsetClosure().SizeValue())
- // Equivalent to (private) offsetof(art::mirror::LambdaProxy, closure_))
-
-// Working with boxed innate lambdas (as a mirror::Object) in raw memory:
-// --- Note that this layout only applies to lambdas originally made with create-lambda.
-// --- Boxing a lambda created from a new-instance instruction is simply the original object.
-//
-// |---------------------|
-// | object header |
-// |---------------------|
-// | lambda::Closure* | <-- long on 64-bit, int on 32-bit
-// |---------------------|
-#define ART_LAMBDA_METHOD_ART_METHOD_OFFSET (0)
-ADD_TEST_EQ(static_cast<size_t>(ART_LAMBDA_METHOD_ART_METHOD_OFFSET),
- art::lambda::ArtLambdaMethod::GetArtMethodOffset())
-
-#if defined(NDEBUG)
-// Release should be faaast. So just jump directly to the lambda method.
-#define LAMBDA_PROXY_SETUP_FRAME 0
-#else
-// Debug can be slower, and we want to get better stack traces. Set up a frame.
-#define LAMBDA_PROXY_SETUP_FRAME 1
-#endif
-
-// For WIP implementation, lambda types are all "longs"
-// which means on a 32-bit implementation we need to fill the argument with 32-bit 0s
-// whenever we invoke a method with a lambda in it.
-// TODO: remove all usages of this once we go to a proper \LambdaType; system.
-#define LAMBDA_INVOKE_USES_LONG 1
#if defined(__cplusplus)
} // End of CheckAsmSupportOffsets.
-} // namespace art
#endif
#endif // ART_RUNTIME_ASM_SUPPORT_H_
diff --git a/runtime/base/allocator.h b/runtime/base/allocator.h
index e2ade07..969f5b9 100644
--- a/runtime/base/allocator.h
+++ b/runtime/base/allocator.h
@@ -53,7 +53,6 @@
kAllocatorTagClassTable,
kAllocatorTagInternTable,
kAllocatorTagLambdaBoxTable,
- kAllocatorTagLambdaProxyClassBoxTable,
kAllocatorTagMaps,
kAllocatorTagLOS,
kAllocatorTagSafeMap,
diff --git a/runtime/base/mutex.cc b/runtime/base/mutex.cc
index 6ca56f5..70bd398 100644
--- a/runtime/base/mutex.cc
+++ b/runtime/base/mutex.cc
@@ -65,7 +65,6 @@
Mutex* Locks::trace_lock_ = nullptr;
Mutex* Locks::unexpected_signal_lock_ = nullptr;
Mutex* Locks::lambda_table_lock_ = nullptr;
-Mutex* Locks::lambda_class_table_lock_ = nullptr;
Uninterruptible Roles::uninterruptible_;
struct AllMutexData {
@@ -955,7 +954,6 @@
DCHECK(trace_lock_ != nullptr);
DCHECK(unexpected_signal_lock_ != nullptr);
DCHECK(lambda_table_lock_ != nullptr);
- DCHECK(lambda_class_table_lock_ != nullptr);
} else {
// Create global locks in level order from highest lock level to lowest.
LockLevel current_lock_level = kInstrumentEntrypointsLock;
@@ -1074,10 +1072,6 @@
DCHECK(lambda_table_lock_ == nullptr);
lambda_table_lock_ = new Mutex("lambda table lock", current_lock_level);
- UPDATE_CURRENT_LOCK_LEVEL(kLambdaClassTableLock);
- DCHECK(lambda_class_table_lock_ == nullptr);
- lambda_class_table_lock_ = new Mutex("lambda class table lock", current_lock_level);
-
UPDATE_CURRENT_LOCK_LEVEL(kAbortLock);
DCHECK(abort_lock_ == nullptr);
abort_lock_ = new Mutex("abort lock", current_lock_level, true);
diff --git a/runtime/base/mutex.h b/runtime/base/mutex.h
index e2d7062..d4c9057 100644
--- a/runtime/base/mutex.h
+++ b/runtime/base/mutex.h
@@ -60,7 +60,6 @@
kUnexpectedSignalLock,
kThreadSuspendCountLock,
kAbortLock,
- kLambdaClassTableLock,
kLambdaTableLock,
kJdwpSocketLock,
kRegionSpaceRegionLock,
@@ -693,10 +692,6 @@
// Allow reader-writer mutual exclusion on the boxed table of lambda objects.
// TODO: this should be a RW mutex lock, except that ConditionVariables don't work with it.
static Mutex* lambda_table_lock_ ACQUIRED_AFTER(mutator_lock_);
-
- // Allow reader-writer mutual exclusion on the boxed table of lambda proxy classes.
- // TODO: this should be a RW mutex lock, except that ConditionVariables don't work with it.
- static Mutex* lambda_class_table_lock_ ACQUIRED_AFTER(lambda_table_lock_);
};
class Roles {
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 8a0d8d4..2dd2a83 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -56,7 +56,6 @@
#include "interpreter/interpreter.h"
#include "jit/jit.h"
#include "jit/jit_code_cache.h"
-#include "lambda/box_class_table.h"
#include "leb128.h"
#include "linear_alloc.h"
#include "mirror/class.h"
@@ -65,7 +64,6 @@
#include "mirror/dex_cache-inl.h"
#include "mirror/field.h"
#include "mirror/iftable-inl.h"
-#include "mirror/lambda_proxy.h"
#include "mirror/method.h"
#include "mirror/object-inl.h"
#include "mirror/object_array-inl.h"
@@ -583,9 +581,6 @@
// Create java.lang.reflect.Proxy root.
SetClassRoot(kJavaLangReflectProxy, FindSystemClass(self, "Ljava/lang/reflect/Proxy;"));
- // Create java.lang.LambdaProxy root.
- SetClassRoot(kJavaLangLambdaProxy, FindSystemClass(self, "Ljava/lang/LambdaProxy;"));
-
// Create java.lang.reflect.Field.class root.
auto* class_root = FindSystemClass(self, "Ljava/lang/reflect/Field;");
CHECK(class_root != nullptr);
@@ -1262,7 +1257,6 @@
}
delete data.allocator;
delete data.class_table;
- delete data.lambda_box_class_table;
}
mirror::PointerArray* ClassLinker::AllocPointerArray(Thread* self, size_t length) {
@@ -1904,10 +1898,8 @@
// Special case to get oat code without overwriting a trampoline.
const void* ClassLinker::GetQuickOatCodeFor(ArtMethod* method) {
CHECK(method->IsInvokable()) << PrettyMethod(method);
- if (method->IsReflectProxyMethod()) {
+ if (method->IsProxyMethod()) {
return GetQuickProxyInvokeHandler();
- } else if (method->IsLambdaProxyMethod()) {
- return GetQuickLambdaProxyInvokeHandler();
}
bool found;
OatFile::OatMethod oat_method = FindOatMethodFor(method, &found);
@@ -3265,7 +3257,7 @@
klass->SetName(soa.Decode<mirror::String*>(name));
klass->SetDexCache(GetClassRoot(kJavaLangReflectProxy)->GetDexCache());
mirror::Class::SetStatus(klass, mirror::Class::kStatusIdx, self);
- std::string descriptor(GetDescriptorForAnyProxy(klass.Get()));
+ std::string descriptor(GetDescriptorForProxy(klass.Get()));
const size_t hash = ComputeModifiedUtf8Hash(descriptor.c_str());
// Needs to be before we insert the class so that the allocator field is set.
@@ -3385,228 +3377,23 @@
decoded_name->ToModifiedUtf8().c_str()));
CHECK_EQ(PrettyField(klass->GetStaticField(1)), throws_field_name);
- CHECK_EQ(klass.Get()->GetInterfacesForAnyProxy(),
+ CHECK_EQ(klass.Get()->GetInterfaces(),
soa.Decode<mirror::ObjectArray<mirror::Class>*>(interfaces));
- CHECK_EQ(klass.Get()->GetThrowsForAnyProxy(),
+ CHECK_EQ(klass.Get()->GetThrows(),
soa.Decode<mirror::ObjectArray<mirror::ObjectArray<mirror::Class>>*>(throws));
}
return klass.Get();
}
-mirror::Class* ClassLinker::CreateLambdaProxyClass(ScopedObjectAccessAlreadyRunnable& soa,
- jstring name,
- jobjectArray interfaces,
- jobject loader,
- jobjectArray methods,
- jobjectArray throws,
- bool* already_exists) {
- DCHECK(already_exists != nullptr);
- *already_exists = false;
-
- Thread* self = soa.Self();
- StackHandleScope<10> hs(self);
-
- // Allocate a new java.lang.Class object for a mirror::Proxy.
- MutableHandle<mirror::Class> klass =
- hs.NewHandle(AllocClass(self, GetClassRoot(kJavaLangClass), sizeof(mirror::Class)));
- if (klass.Get() == nullptr) {
- CHECK(self->IsExceptionPending()); // OOME.
- return nullptr;
- }
- DCHECK(klass->GetClass() != nullptr);
- klass->SetObjectSize(sizeof(mirror::LambdaProxy));
-
- // Set the class access flags incl. preverified, so we do not try to set the flag on the methods.
- klass->SetAccessFlags(kAccClassIsLambdaProxy | kAccPublic | kAccFinal | kAccPreverified);
- klass->SetClassLoader(soa.Decode<mirror::ClassLoader*>(loader));
- DCHECK_EQ(klass->GetPrimitiveType(), Primitive::kPrimNot);
- klass->SetName(soa.Decode<mirror::String*>(name));
- klass->SetDexCache(GetClassRoot(kJavaLangLambdaProxy)->GetDexCache());
- // Set the status to be just before after loading it, but before anything is resolved.
- mirror::Class::SetStatus(klass, mirror::Class::kStatusIdx, self);
- // Convert "foo.bar.baz" string to "Lfoo/bar/baz;"
- std::string type_descriptor(GetDescriptorForAnyProxy(klass.Get()));
-
- mirror::Class* existing;
- {
- const size_t hash = ComputeModifiedUtf8Hash(type_descriptor.c_str());
-
- // Insert the class before loading the fields as the field roots
- // (ArtField::declaring_class_) are only visited from the class
- // table. There can't be any suspend points between inserting the
- // class and setting the field arrays below.
- existing = InsertClass(type_descriptor.c_str(), klass.Get(), hash);
- }
- if (UNLIKELY(existing != nullptr)) {
- // We had already made the lambda proxy previously. Return it.
-
- *already_exists = true;
- return existing;
- // Let the GC clean up the class we had already allocated but isn't being used.
- }
-
- // Needs to be after we insert the class so that the allocator field is set.
- LinearAlloc* const allocator = GetOrCreateAllocatorForClassLoader(klass->GetClassLoader());
-
- // Instance fields are inherited, but we add a couple of static fields...
- LengthPrefixedArray<ArtField>* sfields =
- AllocArtFieldArray(self, allocator, mirror::LambdaProxy::kStaticFieldCount);
- klass->SetSFieldsPtr(sfields);
-
- // 1. Create a static field 'interfaces' that holds the _declared_ interfaces implemented by
- // our proxy, so Class.getInterfaces doesn't return the flattened set.
- // -- private static java.lang.Class[] interfaces; // list of declared interfaces
- ArtField& interfaces_sfield = sfields->At(mirror::LambdaProxy::kStaticFieldIndexInterfaces);
- interfaces_sfield.SetDexFieldIndex(mirror::LambdaProxy::kStaticFieldIndexInterfaces);
- interfaces_sfield.SetDeclaringClass(klass.Get());
- interfaces_sfield.SetAccessFlags(kAccStatic | kAccPublic | kAccFinal);
-
- // 2. Create a static field 'throws' that holds the classes of exceptions thrown by our methods.
- // This is returned by java.lang.reflect.Method#getExceptionTypes()
- // --- private static java.lang.Class[][] throws; // maps vtable id to list of classes.
- ArtField& throws_sfield = sfields->At(mirror::LambdaProxy::kStaticFieldIndexThrows);
- throws_sfield.SetDexFieldIndex(mirror::LambdaProxy::kStaticFieldIndexThrows);
- throws_sfield.SetDeclaringClass(klass.Get());
- throws_sfield.SetAccessFlags(kAccStatic | kAccPublic | kAccFinal);
-
- // Set up the Constructor method.
- {
- // Lambda proxies have 1 direct method, the constructor.
- static constexpr size_t kNumDirectMethods = 1;
- LengthPrefixedArray<ArtMethod>* directs = AllocArtMethodArray(self,
- allocator,
- kNumDirectMethods);
- // Currently AllocArtMethodArray cannot return null, but the OOM logic is left there in case we
- // want to throw OOM in the future.
- if (UNLIKELY(directs == nullptr)) {
- self->AssertPendingOOMException();
- return nullptr;
- }
- klass->SetDirectMethodsPtr(directs);
- CreateLambdaProxyConstructor(klass, klass->GetDirectMethodUnchecked(0, image_pointer_size_));
- }
-
- // Create virtual method using specified prototypes.
- auto h_methods = hs.NewHandle(soa.Decode<mirror::ObjectArray<mirror::Method>*>(methods));
- DCHECK_EQ(h_methods->GetClass(), mirror::Method::ArrayClass())
- << PrettyClass(h_methods->GetClass());
- const size_t num_virtual_methods = h_methods->GetLength();
- auto* virtuals = AllocArtMethodArray(self, allocator, num_virtual_methods);
- // Currently AllocArtMethodArray cannot return null, but the OOM logic is left there in case we
- // want to throw OOM in the future.
- if (UNLIKELY(virtuals == nullptr)) {
- self->AssertPendingOOMException();
- return nullptr;
- }
- klass->SetVirtualMethodsPtr(virtuals);
- size_t abstract_methods = 0;
- for (size_t i = 0; i < num_virtual_methods; ++i) {
- ArtMethod* virtual_method = klass->GetVirtualMethodUnchecked(i, image_pointer_size_);
- ArtMethod* prototype = h_methods->Get(i)->GetArtMethod();
- if (UNLIKELY((prototype->GetAccessFlags() & kAccDefault) != 0)) {
- UNIMPLEMENTED(FATAL) << "Lambda proxies don't support default methods yet";
- }
- if (prototype->IsAbstract()) {
- abstract_methods++;
- }
- VLOG(class_linker) << "Creating lambda proxy method for " << PrettyMethod(prototype);
-
- CreateLambdaProxyMethod(klass, prototype, virtual_method);
- DCHECK(virtual_method->GetDeclaringClass() != nullptr);
- DCHECK(prototype->GetDeclaringClass() != nullptr);
- }
- // Ignore any methods from Object and default methods, it doesn't matter.
- // Sanity check that the prototype interface is indeed compatible with lambdas.
- DCHECK_EQ(abstract_methods, 1u)
- << "Interface must be a single-abstract-method type" << PrettyClass(klass.Get());
-
- // The super class is java.lang.LambdaProxy
- klass->SetSuperClass(GetClassRoot(kJavaLangLambdaProxy));
- // Now effectively in the loaded state.
- mirror::Class::SetStatus(klass, mirror::Class::kStatusLoaded, self);
- self->AssertNoPendingException();
-
- MutableHandle<mirror::Class> new_class = hs.NewHandle<mirror::Class>(nullptr);
- {
- // Must hold lock on object when resolved.
- ObjectLock<mirror::Class> resolution_lock(self, klass);
- // Link the fields and virtual methods, creating vtable and iftables.
- // The new class will replace the old one in the class table.
- Handle<mirror::ObjectArray<mirror::Class>> h_interfaces(
- hs.NewHandle(soa.Decode<mirror::ObjectArray<mirror::Class>*>(interfaces)));
-
- {
- DCHECK_EQ(1, h_interfaces->GetLength()) << "Lambda proxies must implement 1 interface only";
- mirror::Class* single_abstract_interface = h_interfaces->Get(0);
- DCHECK(single_abstract_interface != nullptr);
-
- // Use the dex cache from the interface, which will enable most of the
- // dex-using mechanisms on the class and its methods will work.
- klass->SetDexCache(single_abstract_interface->GetDexCache());
- }
-
- if (!LinkClass(self, type_descriptor.c_str(), klass, h_interfaces, &new_class)) {
- mirror::Class::SetStatus(klass, mirror::Class::kStatusError, self);
- return nullptr;
- }
- }
- CHECK(klass->IsRetired());
- CHECK_NE(klass.Get(), new_class.Get());
- klass.Assign(new_class.Get());
-
- CHECK_EQ(interfaces_sfield.GetDeclaringClass(), klass.Get());
- interfaces_sfield.SetObject<false>(klass.Get(),
- soa.Decode<mirror::ObjectArray<mirror::Class>*>(interfaces));
-
- CHECK_EQ(throws_sfield.GetDeclaringClass(), klass.Get());
- throws_sfield.SetObject<false>(
- klass.Get(), soa.Decode<mirror::ObjectArray<mirror::ObjectArray<mirror::Class> >*>(throws));
-
- {
- // Lock on klass is released. Lock new class object.
- ObjectLock<mirror::Class> initialization_lock(self, klass);
- mirror::Class::SetStatus(klass, mirror::Class::kStatusInitialized, self);
- }
-
- // Sanity checks
- if (kIsDebugBuild) {
- CHECK(klass->GetIFieldsPtr() == nullptr);
- CheckLambdaProxyConstructor(klass->GetDirectMethod(0, image_pointer_size_));
-
- for (size_t i = 0; i < num_virtual_methods; ++i) {
- ArtMethod* virtual_method = klass->GetVirtualMethodUnchecked(i, image_pointer_size_);
- ArtMethod* prototype = h_methods->Get(i++)->GetArtMethod();
- CheckLambdaProxyMethod(virtual_method, prototype);
- }
-
- StackHandleScope<1> hs2(self);
- Handle<mirror::String> decoded_name = hs2.NewHandle(soa.Decode<mirror::String*>(name));
- std::string interfaces_field_name(StringPrintf("java.lang.Class[] %s.interfaces",
- decoded_name->ToModifiedUtf8().c_str()));
- CHECK_EQ(PrettyField(klass->GetStaticField(0)), interfaces_field_name);
-
- std::string throws_field_name(StringPrintf("java.lang.Class[][] %s.throws",
- decoded_name->ToModifiedUtf8().c_str()));
- CHECK_EQ(PrettyField(klass->GetStaticField(1)), throws_field_name);
-
- CHECK_EQ(klass.Get()->GetInterfacesForAnyProxy(),
- soa.Decode<mirror::ObjectArray<mirror::Class>*>(interfaces));
- CHECK_EQ(klass.Get()->GetThrowsForAnyProxy(),
- soa.Decode<mirror::ObjectArray<mirror::ObjectArray<mirror::Class>>*>(throws));
- }
- return klass.Get();
-}
-
-std::string ClassLinker::GetDescriptorForAnyProxy(mirror::Class* proxy_class) {
- DCHECK(proxy_class != nullptr);
- DCHECK(proxy_class->IsAnyProxyClass());
+std::string ClassLinker::GetDescriptorForProxy(mirror::Class* proxy_class) {
+ DCHECK(proxy_class->IsProxyClass());
mirror::String* name = proxy_class->GetName();
DCHECK(name != nullptr);
return DotToDescriptor(name->ToModifiedUtf8().c_str());
}
ArtMethod* ClassLinker::FindMethodForProxy(mirror::Class* proxy_class, ArtMethod* proxy_method) {
- DCHECK(proxy_class->IsAnyProxyClass());
+ DCHECK(proxy_class->IsProxyClass());
DCHECK(proxy_method->IsProxyMethod());
{
Thread* const self = Thread::Current();
@@ -3634,7 +3421,7 @@
void ClassLinker::CreateProxyConstructor(Handle<mirror::Class> klass, ArtMethod* out) {
// Create constructor for Proxy that must initialize the method.
- CHECK_EQ(GetClassRoot(kJavaLangReflectProxy)->NumDirectMethods(), 18u);
+ CHECK_EQ(GetClassRoot(kJavaLangReflectProxy)->NumDirectMethods(), 16u);
ArtMethod* proxy_constructor = GetClassRoot(kJavaLangReflectProxy)->GetDirectMethodUnchecked(
2, image_pointer_size_);
// Ensure constructor is in dex cache so that we can use the dex cache to look up the overridden
@@ -3650,38 +3437,6 @@
out->SetDeclaringClass(klass.Get());
}
-void ClassLinker::CreateLambdaProxyConstructor(Handle<mirror::Class> klass,
- /*out*/ArtMethod* method_constructor) {
- DCHECK(klass.Get() != nullptr);
- DCHECK(method_constructor != nullptr);
-
- // Create constructor for Proxy that must initialize the method.
- // Lambda proxy superclass only has 1 direct method, the constructor (<init>()V)
- CHECK_EQ(GetClassRoot(kJavaLangLambdaProxy)->NumDirectMethods(),
- mirror::LambdaProxy::kDirectMethodCount);
- // Get the constructor method.
- ArtMethod* proxy_constructor = GetClassRoot(kJavaLangLambdaProxy)->GetDirectMethodUnchecked(
- mirror::LambdaProxy::kDirectMethodIndexConstructor,
- image_pointer_size_);
-
- // Verify constructor method is indeed a constructor.
- CHECK(proxy_constructor != nullptr);
-
- // Ensure constructor is in dex cache so that we can use the dex cache to look up the overridden
- // constructor method.
- GetClassRoot(kJavaLangLambdaProxy)->GetDexCache()->SetResolvedMethod(
- proxy_constructor->GetDexMethodIndex(),
- proxy_constructor,
- image_pointer_size_);
-
- // Clone the existing constructor of LambdaProxy
- // (our constructor would just invoke it so steal its code_ too).
- method_constructor->CopyFrom(proxy_constructor, image_pointer_size_);
- // Make this constructor public and fix the class to be our LambdaProxy version
- method_constructor->SetAccessFlags((method_constructor->GetAccessFlags() & ~kAccProtected) | kAccPublic);
- method_constructor->SetDeclaringClass(klass.Get());
-}
-
void ClassLinker::CheckProxyConstructor(ArtMethod* constructor) const {
CHECK(constructor->IsConstructor());
auto* np = constructor->GetInterfaceMethodIfProxy(image_pointer_size_);
@@ -3690,14 +3445,6 @@
DCHECK(constructor->IsPublic());
}
-void ClassLinker::CheckLambdaProxyConstructor(ArtMethod* constructor) const {
- CHECK(constructor->IsConstructor());
- auto* np = constructor->GetInterfaceMethodIfProxy(image_pointer_size_);
- CHECK_STREQ(np->GetName(), "<init>");
- CHECK_STREQ(np->GetSignature().ToString().c_str(), "()V");
- DCHECK(constructor->IsPublic());
-}
-
void ClassLinker::CreateProxyMethod(Handle<mirror::Class> klass, ArtMethod* prototype,
ArtMethod* out) {
// Ensure prototype is in dex cache so that we can use the dex cache to look up the overridden
@@ -3709,7 +3456,6 @@
dex_cache->SetResolvedMethod(
prototype->GetDexMethodIndex(), prototype, image_pointer_size_);
}
-
// We steal everything from the prototype (such as DexCache, invoke stub, etc.) then specialize
// as necessary
DCHECK(out != nullptr);
@@ -3725,42 +3471,6 @@
out->SetEntryPointFromQuickCompiledCode(GetQuickProxyInvokeHandler());
}
-void ClassLinker::CreateLambdaProxyMethod(Handle<mirror::Class> klass,
- ArtMethod* prototype,
- ArtMethod* out) {
- DCHECK(prototype != nullptr);
- DCHECK(out != nullptr);
-
- // DO NOT go through the proxy invoke handler for the default methods. They have no idea
- // how to handle the raw closure, so they must get the regular object when invoked.
- CHECK_EQ(prototype->GetAccessFlags() & kAccDefault, 0u) << "Default methods must not be proxied";
-
- // Ensure prototype is in dex cache so that we can use the dex cache to look up the overridden
- // prototype method
- auto* dex_cache = prototype->GetDeclaringClass()->GetDexCache();
- // Avoid dirtying the dex cache unless we need to.
- if (dex_cache->GetResolvedMethod(prototype->GetDexMethodIndex(), image_pointer_size_) !=
- prototype) {
- dex_cache->SetResolvedMethod(
- prototype->GetDexMethodIndex(), prototype, image_pointer_size_);
- }
- // We steal everything from the prototype (such as DexCache, invoke stub, etc.) then specialize
- // as necessary
- out->CopyFrom(prototype, image_pointer_size_);
-
- // Set class to be the concrete proxy class and clear the abstract flag, modify exceptions to
- // the intersection of throw exceptions as defined in Proxy
- out->SetDeclaringClass(klass.Get());
- out->SetAccessFlags((out->GetAccessFlags() & ~kAccAbstract) | kAccFinal);
-
- // Setting the entry point isn't safe for AOT since ASLR loads it anywhere at runtime.
- CHECK(!Runtime::Current()->IsAotCompiler());
-
- // At runtime the method looks like a reference and argument saving method, clone the code
- // related parameters from this method.
- out->SetEntryPointFromQuickCompiledCode(GetQuickLambdaProxyInvokeHandler());
-}
-
void ClassLinker::CheckProxyMethod(ArtMethod* method, ArtMethod* prototype) const {
// Basic sanity
CHECK(!prototype->IsFinal());
@@ -3782,11 +3492,6 @@
prototype->GetReturnType(true /* resolve */, image_pointer_size_));
}
-void ClassLinker::CheckLambdaProxyMethod(ArtMethod* method, ArtMethod* prototype) const {
- // same as above.
- return CheckProxyMethod(method, prototype);
-}
-
bool ClassLinker::CanWeInitializeClass(mirror::Class* klass, bool can_init_statics,
bool can_init_parents) {
if (can_init_statics && can_init_parents) {
@@ -4418,9 +4123,7 @@
class_loader->SetClassTable(data.class_table);
// Should have been set when we registered the dex file.
data.allocator = class_loader->GetAllocator();
- CHECK(class_loader->GetLambdaProxyCache() == nullptr);
- data.lambda_box_class_table = new lambda::BoxClassTable();
- class_loader->SetLambdaProxyCache(data.lambda_box_class_table);
+ CHECK(data.allocator != nullptr);
class_loaders_.push_back(data);
}
return class_table;
@@ -6863,7 +6566,6 @@
"Ljava/lang/reflect/Field;",
"Ljava/lang/reflect/Method;",
"Ljava/lang/reflect/Proxy;",
- "Ljava/lang/LambdaProxy;",
"[Ljava/lang/String;",
"[Ljava/lang/reflect/Constructor;",
"[Ljava/lang/reflect/Field;",
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index f073cd8..29aac31 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -40,11 +40,6 @@
class ImageSpace;
} // namespace space
} // namespace gc
-
-namespace lambda {
- class BoxClassTable;
-} // namespace lambda
-
namespace mirror {
class ClassLoader;
class DexCache;
@@ -87,7 +82,6 @@
kJavaLangReflectField,
kJavaLangReflectMethod,
kJavaLangReflectProxy,
- kJavaLangLambdaProxy,
kJavaLangStringArrayClass,
kJavaLangReflectConstructorArrayClass,
kJavaLangReflectFieldArrayClass,
@@ -430,46 +424,12 @@
jobjectArray methods,
jobjectArray throws)
SHARED_REQUIRES(Locks::mutator_lock_);
-
- // Get the long type descriptor, e.g. "LProxyName$1234;" for the requested proxy class.
- static std::string GetDescriptorForAnyProxy(mirror::Class* proxy_class)
+ std::string GetDescriptorForProxy(mirror::Class* proxy_class)
SHARED_REQUIRES(Locks::mutator_lock_);
ArtMethod* FindMethodForProxy(mirror::Class* proxy_class, ArtMethod* proxy_method)
REQUIRES(!dex_lock_)
SHARED_REQUIRES(Locks::mutator_lock_);
- // Create a lambda proxy class.
- // -- Nominally used when boxing an innate lambda, since that has no corresponding class.
- //
- // * name must be a fully-qualified class name (and dotted), e.g. "java.lang.Runnable"
- // * interfaces is an array of java.lang.Class for interfaces that will be the supertype
- // (note that there must be exactly 1 element here for a lambda interface since lambda
- // types can only target 1 interface).
- // * loader must be a java.lang.ClassLoader where the proxy class will be created
- // * methods must be an array of java.lang.reflect.Method that consists of the
- // deduplicated methods from all of the interfaces specified.
- // * throws must be an array of java.lang.Class[] where each index corresponds to that of
- // methods, and it signifies the "throws" keyword of each method
- // (this is not directly used by the runtime itself, but it is available via reflection).
- //
- // Returns a non-null pointer to a class upon success, otherwise null and throws an exception.
- //
- // If the class was already created previously (with the same name but potentially different
- // parameters), already_exists is set to true; otherwise already_exists is set to false.
- // The already_exists value is undefined when an exception was thrown.
- //
- // Sidenote: interfaces is an array to simplify the libcore code which creates a Java
- // array in an attempt to reduce code duplication.
- // TODO: this should probably also take the target single-abstract-method as well.
- mirror::Class* CreateLambdaProxyClass(ScopedObjectAccessAlreadyRunnable& soa,
- jstring name,
- jobjectArray interfaces,
- jobject loader,
- jobjectArray methods,
- jobjectArray throws,
- /*out*/bool* already_exists)
- SHARED_REQUIRES(Locks::mutator_lock_);
-
// Get the oat code for a method when its class isn't yet initialized
const void* GetQuickOatCodeFor(ArtMethod* method)
SHARED_REQUIRES(Locks::mutator_lock_);
@@ -613,7 +573,6 @@
jweak weak_root; // Weak root to enable class unloading.
ClassTable* class_table;
LinearAlloc* allocator;
- lambda::BoxClassTable* lambda_box_class_table;
};
// Ensures that the supertype of 'klass' ('supertype') is verified. Returns false and throws
@@ -948,12 +907,8 @@
void CheckProxyConstructor(ArtMethod* constructor) const
SHARED_REQUIRES(Locks::mutator_lock_);
- void CheckLambdaProxyConstructor(ArtMethod* constructor) const
- SHARED_REQUIRES(Locks::mutator_lock_);
void CheckProxyMethod(ArtMethod* method, ArtMethod* prototype) const
SHARED_REQUIRES(Locks::mutator_lock_);
- void CheckLambdaProxyMethod(ArtMethod* method, ArtMethod* prototype) const
- SHARED_REQUIRES(Locks::mutator_lock_);
// For use by ImageWriter to find DexCaches for its roots
ReaderWriterMutex* DexLock()
@@ -971,19 +926,9 @@
void CreateProxyConstructor(Handle<mirror::Class> klass, ArtMethod* out)
SHARED_REQUIRES(Locks::mutator_lock_);
-
- // Copy the constructor from java.lang.LambdaProxy into the 'klass'.
- // The copy is written into 'method_constructor'.
- void CreateLambdaProxyConstructor(Handle<mirror::Class> klass,
- /*out*/ArtMethod* method_constructor)
- SHARED_REQUIRES(Locks::mutator_lock_);
-
void CreateProxyMethod(Handle<mirror::Class> klass, ArtMethod* prototype, ArtMethod* out)
SHARED_REQUIRES(Locks::mutator_lock_);
- void CreateLambdaProxyMethod(Handle<mirror::Class> klass, ArtMethod* prototype, ArtMethod* out)
- SHARED_REQUIRES(Locks::mutator_lock_);
-
// Ensures that methods have the kAccPreverified bit set. We use the kAccPreverfied bit on the
// class access flags to determine whether this has been done before.
void EnsurePreverifiedMethods(Handle<mirror::Class> c)
@@ -995,10 +940,7 @@
// Returns null if not found.
ClassTable* ClassTableForClassLoader(mirror::ClassLoader* class_loader)
SHARED_REQUIRES(Locks::mutator_lock_, Locks::classlinker_classes_lock_);
-
- // Insert a new class table if not found. Uses bootclasspath if class_loader is null.
- // Returns either the existing table, or the new one if there wasn't one previously
- // (the return value is always non-null).
+ // Insert a new class table if not found.
ClassTable* InsertClassTableForClassLoader(mirror::ClassLoader* class_loader)
SHARED_REQUIRES(Locks::mutator_lock_)
REQUIRES(Locks::classlinker_classes_lock_);
diff --git a/runtime/class_linker_test.cc b/runtime/class_linker_test.cc
index 4a9db1d..2c086c5 100644
--- a/runtime/class_linker_test.cc
+++ b/runtime/class_linker_test.cc
@@ -31,7 +31,6 @@
#include "mirror/class-inl.h"
#include "mirror/dex_cache.h"
#include "mirror/field.h"
-#include "mirror/lambda_proxy.h"
#include "mirror/object-inl.h"
#include "mirror/object_array-inl.h"
#include "mirror/proxy.h"
@@ -553,7 +552,6 @@
ClassLoaderOffsets() : CheckOffsets<mirror::ClassLoader>(false, "Ljava/lang/ClassLoader;") {
addOffset(OFFSETOF_MEMBER(mirror::ClassLoader, allocator_), "allocator");
addOffset(OFFSETOF_MEMBER(mirror::ClassLoader, class_table_), "classTable");
- addOffset(OFFSETOF_MEMBER(mirror::ClassLoader, lambda_proxy_cache_), "lambdaProxyCache");
addOffset(OFFSETOF_MEMBER(mirror::ClassLoader, packages_), "packages");
addOffset(OFFSETOF_MEMBER(mirror::ClassLoader, parent_), "parent");
addOffset(OFFSETOF_MEMBER(mirror::ClassLoader, proxyCache_), "proxyCache");
@@ -566,13 +564,6 @@
};
};
-struct LambdaProxyOffsets : public CheckOffsets<mirror::LambdaProxy> {
- LambdaProxyOffsets() : CheckOffsets<mirror::LambdaProxy>(false, "Ljava/lang/LambdaProxy;") {
- addOffset(OFFSETOF_MEMBER(mirror::LambdaProxy, closure_), "closure");
- };
-};
-
-
struct DexCacheOffsets : public CheckOffsets<mirror::DexCache> {
DexCacheOffsets() : CheckOffsets<mirror::DexCache>(false, "Ljava/lang/DexCache;") {
addOffset(OFFSETOF_MEMBER(mirror::DexCache, dex_), "dex");
@@ -648,7 +639,6 @@
EXPECT_TRUE(StackTraceElementOffsets().Check());
EXPECT_TRUE(ClassLoaderOffsets().Check());
EXPECT_TRUE(ProxyOffsets().Check());
- EXPECT_TRUE(LambdaProxyOffsets().Check());
EXPECT_TRUE(DexCacheOffsets().Check());
EXPECT_TRUE(ReferenceOffsets().Check());
EXPECT_TRUE(FinalizerReferenceOffsets().Check());
diff --git a/runtime/common_runtime_test.cc b/runtime/common_runtime_test.cc
index e84313c..f705a50 100644
--- a/runtime/common_runtime_test.cc
+++ b/runtime/common_runtime_test.cc
@@ -55,6 +55,7 @@
// Gtests can be very noisy. For example, an executable with multiple tests will trigger native
// bridge warnings. The following line reduces the minimum log severity to ERROR and suppresses
// everything else. In case you want to see all messages, comment out the line.
+ setenv("ANDROID_LOG_TAGS", "*:e", 1);
art::InitLogging(argv);
LOG(::art::INFO) << "Running main() from common_runtime_test.cc...";
diff --git a/runtime/entrypoints/entrypoint_utils.cc b/runtime/entrypoints/entrypoint_utils.cc
index 2a92226..87e29ae 100644
--- a/runtime/entrypoints/entrypoint_utils.cc
+++ b/runtime/entrypoints/entrypoint_utils.cc
@@ -313,7 +313,7 @@
reinterpret_cast<uintptr_t>(virtual_methods)) / method_size;
CHECK_LT(throws_index, static_cast<int>(num_virtuals));
mirror::ObjectArray<mirror::Class>* declared_exceptions =
- proxy_class->GetThrowsForAnyProxy()->Get(throws_index);
+ proxy_class->GetThrows()->Get(throws_index);
mirror::Class* exception_class = exception->GetClass();
bool declares_exception = false;
for (int32_t i = 0; i < declared_exceptions->GetLength() && !declares_exception; i++) {
diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
index 8c2dc3e..abf9ac4 100644
--- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
@@ -23,12 +23,9 @@
#include "entrypoints/runtime_asm_entrypoints.h"
#include "gc/accounting/card_table-inl.h"
#include "interpreter/interpreter.h"
-#include "lambda/closure.h"
-#include "lambda/art_lambda_method.h"
#include "method_reference.h"
#include "mirror/class-inl.h"
#include "mirror/dex_cache-inl.h"
-#include "mirror/lambda_proxy.h"
#include "mirror/method.h"
#include "mirror/object-inl.h"
#include "mirror/object_array-inl.h"
@@ -297,8 +294,7 @@
// 1st GPR.
static mirror::Object* GetProxyThisObject(ArtMethod** sp)
SHARED_REQUIRES(Locks::mutator_lock_) {
- // TODO: Lambda proxies only set up a frame when debugging
- CHECK((*sp)->IsReflectProxyMethod() || ((*sp)->IsLambdaProxyMethod() /*&& kIsDebugBuild*/));
+ CHECK((*sp)->IsProxyMethod());
CHECK_GT(kNumQuickGprArgs, 0u);
constexpr uint32_t kThisGprIndex = 0u; // 'this' is in the 1st GPR.
size_t this_arg_offset = kQuickCalleeSaveFrame_RefAndArgs_Gpr1Offset +
@@ -838,9 +834,8 @@
extern "C" uint64_t artQuickProxyInvokeHandler(
ArtMethod* proxy_method, mirror::Object* receiver, Thread* self, ArtMethod** sp)
SHARED_REQUIRES(Locks::mutator_lock_) {
- DCHECK(proxy_method->GetDeclaringClass()->IsReflectProxyClass()) << PrettyMethod(proxy_method);
- DCHECK(proxy_method->IsReflectProxyMethod()) << PrettyMethod(proxy_method);
- DCHECK(receiver->GetClass()->IsReflectProxyClass()) << PrettyMethod(proxy_method);
+ DCHECK(proxy_method->IsProxyMethod()) << PrettyMethod(proxy_method);
+ DCHECK(receiver->GetClass()->IsProxyClass()) << PrettyMethod(proxy_method);
// Ensure we don't get thread suspension until the object arguments are safely in jobjects.
const char* old_cause =
self->StartAssertNoThreadSuspension("Adding to IRT proxy object arguments");
@@ -883,175 +878,6 @@
return result.GetJ();
}
-extern "C" uint64_t artQuickLambdaProxyInvokeHandler(
- ArtMethod* proxy_method, mirror::LambdaProxy* receiver, Thread* self, ArtMethod** sp)
- SHARED_REQUIRES(Locks::mutator_lock_) {
- using lambda::ShortyFieldType;
-
- DCHECK(proxy_method->GetDeclaringClass()->IsLambdaProxyClass()) << PrettyMethod(proxy_method);
- DCHECK(proxy_method->IsLambdaProxyMethod()) << PrettyMethod(proxy_method);
- DCHECK(receiver->GetClass()->IsLambdaProxyClass()) << PrettyMethod(proxy_method);
-
- lambda::Closure* lambda_closure = receiver->GetClosure();
- DCHECK(lambda_closure != nullptr); // Should've NPEd during the invoke-interface.
- // Learned lambdas have their own implementation of the SAM, they must not go through here.
- DCHECK(lambda_closure->GetLambdaInfo()->IsInnateLambda());
- ArtMethod* target_method = lambda_closure->GetTargetMethod();
-
- // Lambda targets are always static.
- // TODO: This should really be a target_method->IsLambda(), once we add the access flag.
- CHECK(target_method->IsStatic()) << PrettyMethod(proxy_method) << " "
- << PrettyMethod(target_method);
-
- // Ensure we don't get thread suspension until the object arguments are safely in jobjects.
- const char* old_cause =
- self->StartAssertNoThreadSuspension("Adding to IRT/SF lambda proxy object arguments");
- // Register the top of the managed stack, making stack crawlable.
- DCHECK_EQ((*sp), proxy_method) << PrettyMethod(proxy_method);
- self->VerifyStack();
- // Start new JNI local reference state.
- JNIEnvExt* env = self->GetJniEnv();
- ScopedObjectAccessUnchecked soa(env);
-
- // Placing arguments into args vector and remove the receiver.
- ArtMethod* non_proxy_method = proxy_method->GetInterfaceMethodIfProxy(sizeof(void*));
- CHECK(!non_proxy_method->IsStatic()) << PrettyMethod(proxy_method) << " "
- << PrettyMethod(non_proxy_method);
- uint32_t shorty_len = 0;
- const char* shorty = non_proxy_method->GetShorty(/*out*/&shorty_len);
-
- std::vector<jvalue> args;
- // Make a quick visitor so we can restore the refs incase they move after a GC.
- BuildQuickArgumentVisitor local_ref_visitor(sp,
- false /*is_static*/,
- shorty,
- shorty_len,
- &soa,
- /*out*/&args);
- local_ref_visitor.VisitArguments();
-
- static_assert(lambda::kClosureIsStoredAsLong,
- "Need to update this code once closures are no "
- "longer treated as a 'long' in quick abi");
-
- // Allocate one vreg more than usual because we need to convert our
- // receiver Object (1 vreg) into a long (2 vregs).
- // TODO: Ugly... move to traits instead?
- const uint32_t first_arg_reg = ShortyFieldType(ShortyFieldType::kLambda).GetVirtualRegisterCount()
- - ShortyFieldType(ShortyFieldType::kObject).GetVirtualRegisterCount();
- const uint32_t num_vregs = lambda_closure->GetLambdaInfo()->GetArgumentVRegCount();
- DCHECK_GE(num_vregs, first_arg_reg);
- if (kIsDebugBuild) {
- const char* method_shorty = non_proxy_method->GetShorty();
- DCHECK_NE(*method_shorty, '\0') << method_shorty;
- const char* arg_shorty = method_shorty + 1; // Skip return type.
-
- // Proxy method should have an object (1 vreg) receiver,
- // Lambda method should have a lambda (2 vregs) receiver.
- // -- All other args are the same as before.
- // -- Make sure vreg count is what we thought it was.
- uint32_t non_proxy_num_vregs =
- ShortyFieldType::CountVirtualRegistersRequired(arg_shorty) // doesn't count receiver
- + ShortyFieldType(ShortyFieldType::kObject).GetVirtualRegisterCount(); // implicit receiver
-
- CHECK_EQ(non_proxy_num_vregs + first_arg_reg, num_vregs)
- << PrettyMethod(non_proxy_method) << " " << PrettyMethod(lambda_closure->GetTargetMethod());
- }
-
- ShadowFrameAllocaUniquePtr shadow_frame = CREATE_SHADOW_FRAME(num_vregs,
- /*link*/nullptr,
- target_method,
- /*dex_pc*/0);
-
- // Copy our proxy method caller's arguments into this ShadowFrame.
- BuildQuickShadowFrameVisitor local_sf_visitor(sp,
- /*is_static*/false,
- shorty,
- shorty_len,
- shadow_frame.get(),
- first_arg_reg);
-
- local_sf_visitor.VisitArguments();
- // Now fix up the arguments, with each ArgK being a vreg:
-
- // (Before):
- // Arg0 = proxy receiver (LambdaProxy)
- // Arg1 = first-user defined argument
- // Arg2 = second user-defined argument
- // ....
- // ArgN = ...
-
- // (After)
- // Arg0 = closure (hi)
- // Arg1 = closure (lo) = 0x00 on 32-bit
- // Arg2 = <?> (first user-defined argument)
- // Arg3 = <?> (first user-defined argument)
- // ...
- // argN+1 = ...
-
- // Transformation diagram:
- /*
- Arg0 Arg2 Arg3 ... ArgN
- | \ \ \
- | \ \ \
- ClHi ClLo Arg2 Arg3 ... ArgN:
- */
-
- // 1) memmove vregs 1-N into 2-N+1
- uint32_t* shadow_frame_vregs = shadow_frame->GetVRegArgs(/*i*/0);
- if (lambda::kClosureIsStoredAsLong ||
- sizeof(void*) != sizeof(mirror::CompressedReference<mirror::LambdaProxy>)) {
- // Suspending here would be very bad since we are doing a raw memmove
-
- // Move the primitive vregs over.
- {
- size_t shadow_frame_vregs_size = num_vregs;
- memmove(shadow_frame_vregs + first_arg_reg,
- shadow_frame_vregs,
- shadow_frame_vregs_size - first_arg_reg);
- }
-
- // Move the reference vregs over.
- if (LIKELY(shadow_frame->HasReferenceArray())) {
- uint32_t* shadow_frame_references = shadow_frame_vregs + num_vregs;
- size_t shadow_frame_references_size = num_vregs;
- memmove(shadow_frame_references + first_arg_reg,
- shadow_frame_references,
- shadow_frame_references_size - first_arg_reg);
- }
-
- static_assert(lambda::kClosureSupportsReadBarrier == false,
- "Using this memmove code with a read barrier GC seems like it could be unsafe.");
-
- static_assert(sizeof(mirror::CompressedReference<mirror::LambdaProxy>) == sizeof(uint32_t),
- "This block of code assumes a compressed reference fits into exactly 1 vreg");
- }
- // 2) replace proxy receiver with lambda
- shadow_frame->SetVRegLong(0, static_cast<int64_t>(reinterpret_cast<uintptr_t>(lambda_closure)));
-
- // OK: After we do the invoke, the target method takes over managing the arguments
- // and we won't ever access the shadow frame again (if any references moved).
- self->EndAssertNoThreadSuspension(old_cause);
-
- // The shadow frame vreg contents are now 'owned' by the Invoke method, and
- // will be managed by it during a GC despite being a raw uint32_t array.
- // We however have no guarantee that it is updated on the way out, so do not read out of the
- // shadow frame after this call.
- JValue result;
- target_method->Invoke(self,
- shadow_frame_vregs,
- num_vregs * sizeof(uint32_t),
- /*out*/&result,
- target_method->GetShorty());
-
- // Restore references on the proxy caller stack frame which might have moved.
- // -- This is necessary because the QuickFrameInfo is just the generic runtime "RefsAndArgs"
- // which means that the regular stack visitor wouldn't know how to GC-move any references
- // that we spilled ourselves in the proxy stub.
- local_ref_visitor.FixupReferences();
- return result.GetJ();
-}
-
// Read object references held in arguments from quick frames and place in a JNI local references,
// so they don't get garbage collected.
class RememberForGcArgumentVisitor FINAL : public QuickArgumentVisitor {
diff --git a/runtime/entrypoints/runtime_asm_entrypoints.h b/runtime/entrypoints/runtime_asm_entrypoints.h
index 1ef7585..2842c5a 100644
--- a/runtime/entrypoints/runtime_asm_entrypoints.h
+++ b/runtime/entrypoints/runtime_asm_entrypoints.h
@@ -17,10 +17,6 @@
#ifndef ART_RUNTIME_ENTRYPOINTS_RUNTIME_ASM_ENTRYPOINTS_H_
#define ART_RUNTIME_ENTRYPOINTS_RUNTIME_ASM_ENTRYPOINTS_H_
-// Define entry points to assembly routines.
-// All extern "C" functions here are defined in a corresponding assembly-only file.
-// The exact file paths are runtime/arch/$ISA/quick_entrypoints_$ISA.s
-
namespace art {
#ifndef BUILDING_LIBART
@@ -56,13 +52,6 @@
return reinterpret_cast<const void*>(art_quick_proxy_invoke_handler);
}
-// Return the address of quick stub code for handling transitions into the lambda proxy
-// invoke handler.
-extern "C" void art_quick_lambda_proxy_invoke_handler();
-static inline const void* GetQuickLambdaProxyInvokeHandler() {
- return reinterpret_cast<const void*>(art_quick_lambda_proxy_invoke_handler);
-}
-
// Return the address of quick stub code for resolving a method at first call.
extern "C" void art_quick_resolution_trampoline(ArtMethod*);
static inline const void* GetQuickResolutionStub() {
diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc
index 07f0628..da9a79e 100644
--- a/runtime/gc/heap.cc
+++ b/runtime/gc/heap.cc
@@ -672,8 +672,8 @@
return result;
} else if (UNLIKELY(klass->IsPrimitive<kVerifyNone>())) {
return Primitive::Descriptor(klass->GetPrimitiveType<kVerifyNone>());
- } else if (UNLIKELY(klass->IsAnyProxyClass<kVerifyNone>())) {
- return Runtime::Current()->GetClassLinker()->GetDescriptorForAnyProxy(klass);
+ } else if (UNLIKELY(klass->IsProxyClass<kVerifyNone>())) {
+ return Runtime::Current()->GetClassLinker()->GetDescriptorForProxy(klass);
} else {
mirror::DexCache* dex_cache = klass->GetDexCache<kVerifyNone>();
if (!IsValidContinuousSpaceObjectAddress(dex_cache)) {
diff --git a/runtime/interpreter/interpreter_common.h b/runtime/interpreter/interpreter_common.h
index 2de8e7e..9f6699f 100644
--- a/runtime/interpreter/interpreter_common.h
+++ b/runtime/interpreter/interpreter_common.h
@@ -888,56 +888,12 @@
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,
- class_name.c_str(),
- current_class_loader.Get());
+ Runtime::Current()->GetLambdaBoxTable()->BoxLambda(lambda_closure);
// 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;
}
diff --git a/runtime/interpreter/interpreter_switch_impl.cc b/runtime/interpreter/interpreter_switch_impl.cc
index 11a8c2e..bf95a0e 100644
--- a/runtime/interpreter/interpreter_switch_impl.cc
+++ b/runtime/interpreter/interpreter_switch_impl.cc
@@ -102,8 +102,6 @@
size_t lambda_captured_variable_index = 0;
while (true) {
dex_pc = inst->GetDexPc(insns);
- DCHECK_LE(dex_pc, code_item->insns_size_in_code_units_)
- << "Dex PC overflowed code item size; missing return instruction?";
shadow_frame.SetDexPC(dex_pc);
TraceExecution(shadow_frame, inst, dex_pc);
inst_data = inst->Fetch16(0);
diff --git a/runtime/lambda/art_lambda_method.cc b/runtime/lambda/art_lambda_method.cc
index 0690cd1..6f9f8bb 100644
--- a/runtime/lambda/art_lambda_method.cc
+++ b/runtime/lambda/art_lambda_method.cc
@@ -14,7 +14,6 @@
* limitations under the License.
*/
-#include "art_method-inl.h"
#include "lambda/art_lambda_method.h"
#include "base/logging.h"
@@ -74,12 +73,5 @@
}
}
-size_t ArtLambdaMethod::GetArgumentVRegCount() const {
- DCHECK(GetArtMethod()->IsStatic()); // Instance methods don't have receiver in shorty.
- const char* method_shorty = GetArtMethod()->GetShorty();
- DCHECK_NE(*method_shorty, '\0') << method_shorty;
- return ShortyFieldType::CountVirtualRegistersRequired(method_shorty + 1); // skip return type
-}
-
} // namespace lambda
} // namespace art
diff --git a/runtime/lambda/art_lambda_method.h b/runtime/lambda/art_lambda_method.h
index a858bf9..ea13eb7 100644
--- a/runtime/lambda/art_lambda_method.h
+++ b/runtime/lambda/art_lambda_method.h
@@ -90,17 +90,6 @@
return strlen(captured_variables_shorty_);
}
- // Return the offset in bytes from the start of ArtLambdaMethod to the method_.
- // -- Only should be used by assembly (stubs) support code and compiled code.
- static constexpr size_t GetArtMethodOffset() {
- return offsetof(ArtLambdaMethod, method_);
- }
-
- // Calculate how many vregs all the arguments will use when doing an invoke.
- // (Most primitives are 1 vregs, double/long are 2, reference is 1, lambda is 2).
- // -- This is used to know how big to set up shadow frame when invoking into the target method.
- size_t GetArgumentVRegCount() const SHARED_REQUIRES(Locks::mutator_lock_);
-
private:
// TODO: ArtMethod, or at least the entry points should be inlined into this struct
// to avoid an extra indirect load when doing invokes.
diff --git a/runtime/lambda/box_class_table-inl.h b/runtime/lambda/box_class_table-inl.h
deleted file mode 100644
index 2fc34a7..0000000
--- a/runtime/lambda/box_class_table-inl.h
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * 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_BOX_CLASS_TABLE_INL_H_
-#define ART_RUNTIME_LAMBDA_BOX_CLASS_TABLE_INL_H_
-
-#include "lambda/box_class_table.h"
-#include "thread.h"
-
-namespace art {
-namespace lambda {
-
-template <typename Visitor>
-inline void BoxClassTable::VisitRoots(const Visitor& visitor) {
- MutexLock mu(Thread::Current(), *Locks::lambda_class_table_lock_);
- for (std::pair<UnorderedMapKeyType, ValueType>& key_value : map_) {
- ValueType& gc_root = key_value.second;
- visitor.VisitRoot(gc_root.AddressWithoutBarrier());
- }
-}
-
-} // namespace lambda
-} // namespace art
-
-#endif // ART_RUNTIME_LAMBDA_BOX_CLASS_TABLE_INL_H_
diff --git a/runtime/lambda/box_class_table.cc b/runtime/lambda/box_class_table.cc
deleted file mode 100644
index 1e49886..0000000
--- a/runtime/lambda/box_class_table.cc
+++ /dev/null
@@ -1,204 +0,0 @@
-/*
- * 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 "lambda/box_class_table.h"
-
-#include "base/mutex.h"
-#include "common_throws.h"
-#include "gc_root-inl.h"
-#include "lambda/closure.h"
-#include "lambda/leaking_allocator.h"
-#include "mirror/method.h"
-#include "mirror/object-inl.h"
-#include "thread.h"
-
-#include <string>
-#include <vector>
-
-namespace art {
-namespace lambda {
-
-// Create the lambda proxy class given the name of the lambda interface (e.g. Ljava/lang/Runnable;)
-// Also needs a proper class loader (or null for bootclasspath) where the proxy will be created
-// into.
-//
-// The class must **not** have already been created.
-// Returns a non-null ptr on success, otherwise returns null and has an exception set.
-static mirror::Class* CreateClass(Thread* self,
- const std::string& class_name,
- const Handle<mirror::ClassLoader>& class_loader)
- SHARED_REQUIRES(Locks::mutator_lock_) {
- ScopedObjectAccessUnchecked soa(self);
- StackHandleScope<2> hs(self);
-
- ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
-
- // Find the java.lang.Class for our class name (from the class loader).
- Handle<mirror::Class> lambda_interface =
- hs.NewHandle(class_linker->FindClass(self, class_name.c_str(), class_loader));
- // TODO: use LookupClass in a loop
- // TODO: DCHECK That this doesn't actually cause the class to be loaded,
- // since the create-lambda should've loaded it already
- DCHECK(lambda_interface.Get() != nullptr) << "CreateClass with class_name=" << class_name;
- DCHECK(lambda_interface->IsInterface()) << "CreateClass with class_name=" << class_name;
- jobject lambda_interface_class = soa.AddLocalReference<jobject>(lambda_interface.Get());
-
- // Look up java.lang.reflect.Proxy#getLambdaProxyClass method.
- Handle<mirror::Class> java_lang_reflect_proxy =
- hs.NewHandle(class_linker->FindSystemClass(soa.Self(), "Ljava/lang/reflect/Proxy;"));
- jclass java_lang_reflect_proxy_class =
- soa.AddLocalReference<jclass>(java_lang_reflect_proxy.Get());
- DCHECK(java_lang_reflect_proxy.Get() != nullptr);
-
- jmethodID proxy_factory_method_id =
- soa.Env()->GetStaticMethodID(java_lang_reflect_proxy_class,
- "getLambdaProxyClass",
- "(Ljava/lang/ClassLoader;Ljava/lang/Class;)Ljava/lang/Class;");
- DCHECK(!soa.Env()->ExceptionCheck());
-
- // Call into the java code to do the hard work of figuring out which methods and throws
- // our lambda interface proxy needs to implement. It then calls back into the class linker
- // on our behalf to make the proxy itself.
- jobject generated_lambda_proxy_class =
- soa.Env()->CallStaticObjectMethod(java_lang_reflect_proxy_class,
- proxy_factory_method_id,
- class_loader.ToJObject(),
- lambda_interface_class);
-
- // This can throw in which case we return null. Caller must handle.
- return soa.Decode<mirror::Class*>(generated_lambda_proxy_class);
-}
-
-BoxClassTable::BoxClassTable() {
-}
-
-BoxClassTable::~BoxClassTable() {
- // Don't need to do anything, classes are deleted automatically by GC
- // when the classloader is deleted.
- //
- // Our table will not outlive the classloader since the classloader owns it.
-}
-
-mirror::Class* BoxClassTable::GetOrCreateBoxClass(const char* class_name,
- const Handle<mirror::ClassLoader>& class_loader) {
- DCHECK(class_name != nullptr);
-
- Thread* self = Thread::Current();
-
- std::string class_name_str = class_name;
-
- {
- MutexLock mu(self, *Locks::lambda_class_table_lock_);
-
- // Attempt to look up this class, it's possible it was already created previously.
- // If this is the case we *must* return the same class as before to maintain
- // referential equality between box instances.
- //
- // In managed code:
- // Functional f = () -> 5; // vF = create-lambda
- // Object a = f; // vA = box-lambda vA
- // Object b = f; // vB = box-lambda vB
- // assert(a.getClass() == b.getClass())
- // assert(a == b)
- ValueType value = FindBoxedClass(class_name_str);
- if (!value.IsNull()) {
- return value.Read();
- }
- }
-
- // Otherwise we need to generate a class ourselves and insert it into the hash map
-
- // Release the table lock here, which implicitly allows other threads to suspend
- // (since the GC callbacks will not block on trying to acquire our lock).
- // We also don't want to call into the class linker with the lock held because
- // our lock level is lower.
- self->AllowThreadSuspension();
-
- // Create a lambda proxy class, within the specified class loader.
- mirror::Class* lambda_proxy_class = CreateClass(self, class_name_str, class_loader);
-
- // There are no thread suspension points after this, so we don't need to put it into a handle.
- ScopedAssertNoThreadSuspension soants{self, "BoxClassTable::GetOrCreateBoxClass"}; // NOLINT: [readability/braces] [4]
-
- if (UNLIKELY(lambda_proxy_class == nullptr)) {
- // Most likely an OOM has occurred.
- CHECK(self->IsExceptionPending());
- return nullptr;
- }
-
- {
- MutexLock mu(self, *Locks::lambda_class_table_lock_);
-
- // Possible, but unlikely, that someone already came in and made a proxy class
- // on another thread.
- ValueType value = FindBoxedClass(class_name_str);
- if (UNLIKELY(!value.IsNull())) {
- DCHECK_EQ(lambda_proxy_class, value.Read());
- return value.Read();
- }
-
- // Otherwise we made a brand new proxy class.
- // The class itself is cleaned up by the GC (e.g. class unloading) later.
-
- // Actually insert into the table.
- map_.Insert({std::move(class_name_str), ValueType(lambda_proxy_class)});
- }
-
- return lambda_proxy_class;
-}
-
-BoxClassTable::ValueType BoxClassTable::FindBoxedClass(const std::string& class_name) const {
- auto map_iterator = map_.Find(class_name);
- if (map_iterator != map_.end()) {
- const std::pair<UnorderedMapKeyType, ValueType>& key_value_pair = *map_iterator;
- const ValueType& value = key_value_pair.second;
-
- DCHECK(!value.IsNull()); // Never store null boxes.
- return value;
- }
-
- return ValueType(nullptr);
-}
-
-void BoxClassTable::EmptyFn::MakeEmpty(std::pair<UnorderedMapKeyType, ValueType>& item) const {
- item.first.clear();
-
- Locks::mutator_lock_->AssertSharedHeld(Thread::Current());
- item.second = ValueType(); // Also clear the GC root.
-}
-
-bool BoxClassTable::EmptyFn::IsEmpty(const std::pair<UnorderedMapKeyType, ValueType>& item) const {
- bool is_empty = item.first.empty();
- DCHECK_EQ(item.second.IsNull(), is_empty);
-
- return is_empty;
-}
-
-bool BoxClassTable::EqualsFn::operator()(const UnorderedMapKeyType& lhs,
- const UnorderedMapKeyType& rhs) const {
- // Be damn sure the classes don't just move around from under us.
- Locks::mutator_lock_->AssertSharedHeld(Thread::Current());
-
- // Being the same class name isn't enough, must also have the same class loader.
- // When we are in the same class loader, classes are equal via the pointer.
- return lhs == rhs;
-}
-
-size_t BoxClassTable::HashFn::operator()(const UnorderedMapKeyType& key) const {
- return std::hash<std::string>()(key);
-}
-
-} // namespace lambda
-} // namespace art
diff --git a/runtime/lambda/box_class_table.h b/runtime/lambda/box_class_table.h
deleted file mode 100644
index 17e1026..0000000
--- a/runtime/lambda/box_class_table.h
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * 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_BOX_CLASS_TABLE_H_
-#define ART_RUNTIME_LAMBDA_BOX_CLASS_TABLE_H_
-
-#include "base/allocator.h"
-#include "base/hash_map.h"
-#include "gc_root.h"
-#include "base/macros.h"
-#include "base/mutex.h"
-#include "object_callbacks.h"
-
-#include <stdint.h>
-
-namespace art {
-
-class ArtMethod; // forward declaration
-template<class T> class Handle; // forward declaration
-
-namespace mirror {
-class Class; // forward declaration
-class ClassLoader; // forward declaration
-class LambdaProxy; // forward declaration
-class Object; // forward declaration
-} // namespace mirror
-
-namespace lambda {
-struct Closure; // forward declaration
-
-/*
- * Store a table of boxed lambdas. This is required to maintain object referential equality
- * when a lambda is re-boxed.
- *
- * Conceptually, we store a mapping of Class Name -> Weak Reference<Class>.
- * When too many objects get GCd, we shrink the underlying table to use less space.
- */
-class BoxClassTable FINAL {
- public:
- // TODO: This should take a LambdaArtMethod instead, read class name from that.
- // Note: null class_loader means bootclasspath.
- mirror::Class* GetOrCreateBoxClass(const char* class_name,
- const Handle<mirror::ClassLoader>& class_loader)
- REQUIRES(!Locks::lambda_class_table_lock_, !Roles::uninterruptible_)
- SHARED_REQUIRES(Locks::mutator_lock_);
-
- // Sweep strong references to lambda class boxes. Update the addresses if the objects
- // have been moved, and delete them from the table if the objects have been cleaned up.
- template <typename Visitor>
- void VisitRoots(const Visitor& visitor)
- NO_THREAD_SAFETY_ANALYSIS // for object marking requiring heap bitmap lock
- REQUIRES(!Locks::lambda_class_table_lock_)
- SHARED_REQUIRES(Locks::mutator_lock_);
-
- BoxClassTable();
- ~BoxClassTable();
-
- private:
- // We only store strong GC roots in our table.
- using ValueType = GcRoot<mirror::Class>;
-
- // Attempt to look up the class in the map, or return null if it's not there yet.
- ValueType FindBoxedClass(const std::string& class_name) const
- SHARED_REQUIRES(Locks::lambda_class_table_lock_);
-
- // Store the key as a string so that we can have our own copy of the class name.
- using UnorderedMapKeyType = std::string;
-
- // EmptyFn implementation for art::HashMap
- struct EmptyFn {
- void MakeEmpty(std::pair<UnorderedMapKeyType, ValueType>& item) const
- NO_THREAD_SAFETY_ANALYSIS;
- // SHARED_REQUIRES(Locks::mutator_lock_);
-
- bool IsEmpty(const std::pair<UnorderedMapKeyType, ValueType>& item) const;
- };
-
- // HashFn implementation for art::HashMap
- struct HashFn {
- size_t operator()(const UnorderedMapKeyType& key) const
- NO_THREAD_SAFETY_ANALYSIS;
- // SHARED_REQUIRES(Locks::mutator_lock_);
- };
-
- // EqualsFn implementation for art::HashMap
- struct EqualsFn {
- bool operator()(const UnorderedMapKeyType& lhs, const UnorderedMapKeyType& rhs) const
- NO_THREAD_SAFETY_ANALYSIS;
- // SHARED_REQUIRES(Locks::mutator_lock_);
- };
-
- using UnorderedMap = art::HashMap<UnorderedMapKeyType,
- ValueType,
- EmptyFn,
- HashFn,
- EqualsFn,
- TrackingAllocator<std::pair<UnorderedMapKeyType, ValueType>,
- kAllocatorTagLambdaProxyClassBoxTable>>;
-
- // Map of strong GC roots (lambda interface name -> lambda proxy class)
- UnorderedMap map_ GUARDED_BY(Locks::lambda_class_table_lock_);
-
- // Shrink the map when we get below this load factor.
- // (This is an arbitrary value that should be large enough to prevent aggressive map erases
- // from shrinking the table too often.)
- static constexpr double kMinimumLoadFactor = UnorderedMap::kDefaultMinLoadFactor / 2;
-
- DISALLOW_COPY_AND_ASSIGN(BoxClassTable);
-};
-
-} // namespace lambda
-} // namespace art
-
-#endif // ART_RUNTIME_LAMBDA_BOX_CLASS_TABLE_H_
diff --git a/runtime/lambda/box_table.cc b/runtime/lambda/box_table.cc
index 0032d08..9918bb7 100644
--- a/runtime/lambda/box_table.cc
+++ b/runtime/lambda/box_table.cc
@@ -18,10 +18,8 @@
#include "base/mutex.h"
#include "common_throws.h"
#include "gc_root-inl.h"
-#include "lambda/box_class_table.h"
#include "lambda/closure.h"
#include "lambda/leaking_allocator.h"
-#include "mirror/lambda_proxy.h"
#include "mirror/method.h"
#include "mirror/object-inl.h"
#include "thread.h"
@@ -30,13 +28,12 @@
namespace art {
namespace lambda {
-// All closures are boxed into a subtype of LambdaProxy which implements the lambda's interface.
-using BoxedClosurePointerType = mirror::LambdaProxy*;
+// Temporarily represent the lambda Closure as its raw bytes in an array.
+// TODO: Generate a proxy class for the closure when boxing the first time.
+using BoxedClosurePointerType = mirror::ByteArray*;
-// Returns the base class for all boxed closures.
-// Note that concrete closure boxes are actually a subtype of mirror::LambdaProxy.
-static mirror::Class* GetBoxedClosureBaseClass() SHARED_REQUIRES(Locks::mutator_lock_) {
- return Runtime::Current()->GetClassLinker()->GetClassRoot(ClassLinker::kJavaLangLambdaProxy);
+static mirror::Class* GetBoxedClosureClass() SHARED_REQUIRES(Locks::mutator_lock_) {
+ return mirror::ByteArray::GetArrayClass();
}
namespace {
@@ -57,14 +54,6 @@
return closure;
}
};
-
- struct DeleterForClosure {
- void operator()(Closure* closure) const {
- ClosureAllocator::Delete(closure);
- }
- };
-
- using UniqueClosurePtr = std::unique_ptr<Closure, DeleterForClosure>;
} // namespace
BoxTable::BoxTable()
@@ -86,9 +75,7 @@
}
}
-mirror::Object* BoxTable::BoxLambda(const ClosureType& closure,
- const char* class_name,
- mirror::ClassLoader* class_loader) {
+mirror::Object* BoxTable::BoxLambda(const ClosureType& closure) {
Thread* self = Thread::Current();
{
@@ -104,7 +91,7 @@
// Functional f = () -> 5; // vF = create-lambda
// Object a = f; // vA = box-lambda vA
// Object b = f; // vB = box-lambda vB
- // assert(a == b)
+ // assert(a == f)
ValueType value = FindBoxedLambda(closure);
if (!value.IsNull()) {
return value.Read();
@@ -113,62 +100,30 @@
// Otherwise we need to box ourselves and insert it into the hash map
}
- // Convert the Closure into a managed object instance, whose supertype of java.lang.LambdaProxy.
-
- // TODO: Boxing a learned lambda (i.e. made with unbox-lambda) should return the original object
- StackHandleScope<2> hs{self}; // NOLINT: [readability/braces] [4]
-
- Handle<mirror::ClassLoader> class_loader_handle = hs.NewHandle(class_loader);
-
// Release the lambda table lock here, so that thread suspension is allowed.
- self->AllowThreadSuspension();
- lambda::BoxClassTable* lambda_box_class_table;
+ // Convert the Closure into a managed byte[] which will serve
+ // as the temporary 'boxed' version of the lambda. This is good enough
+ // to check all the basic object identities that a boxed lambda must retain.
+ // It's also good enough to contain all the captured primitive variables.
- // Find the lambda box class table, which can be in the system class loader if classloader is null
- if (class_loader == nullptr) {
- ScopedObjectAccessUnchecked soa(self);
- mirror::ClassLoader* system_class_loader =
- soa.Decode<mirror::ClassLoader*>(Runtime::Current()->GetSystemClassLoader());
- lambda_box_class_table = system_class_loader->GetLambdaProxyCache();
- } else {
- lambda_box_class_table = class_loader_handle->GetLambdaProxyCache();
- // OK: can't be deleted while we hold a handle to the class loader.
- }
- DCHECK(lambda_box_class_table != nullptr);
+ // TODO: Boxing an innate lambda (i.e. made with create-lambda) should make a proxy class
+ // TODO: Boxing a learned lambda (i.e. made with unbox-lambda) should return the original object
+ BoxedClosurePointerType closure_as_array_object =
+ mirror::ByteArray::Alloc(self, closure->GetSize());
- Handle<mirror::Class> closure_class(hs.NewHandle(
- lambda_box_class_table->GetOrCreateBoxClass(class_name, class_loader_handle)));
- if (UNLIKELY(closure_class.Get() == nullptr)) {
+ // There are no thread suspension points after this, so we don't need to put it into a handle.
+
+ if (UNLIKELY(closure_as_array_object == nullptr)) {
// Most likely an OOM has occurred.
- self->AssertPendingException();
+ CHECK(self->IsExceptionPending());
return nullptr;
}
- BoxedClosurePointerType closure_as_object = nullptr;
- UniqueClosurePtr closure_table_copy;
- // Create an instance of the class, and assign the pointer to the closure into it.
- {
- closure_as_object = down_cast<BoxedClosurePointerType>(closure_class->AllocObject(self));
- if (UNLIKELY(closure_as_object == nullptr)) {
- self->AssertPendingOOMException();
- return nullptr;
- }
-
- // Make a copy of the closure that we will store in the hash map.
- // The proxy instance will also point to this same hash map.
- // Note that the closure pointer is cleaned up only after the proxy is GCd.
- closure_table_copy.reset(ClosureAllocator::Allocate(closure->GetSize()));
- closure_as_object->SetClosure(closure_table_copy.get());
- }
-
- // There are no thread suspension points after this, so we don't need to put it into a handle.
- ScopedAssertNoThreadSuspension soants{self, // NOLINT: [whitespace/braces] [5]
- "box lambda table - box lambda - no more suspensions"}; // NOLINT: [whitespace/braces] [5]
-
- // Write the raw closure data into the proxy instance's copy of the closure.
- closure->CopyTo(closure_table_copy.get(),
- closure->GetSize());
+ // Write the raw closure data into the byte[].
+ closure->CopyTo(closure_as_array_object->GetRawData(sizeof(uint8_t), // component size
+ 0 /*index*/), // index
+ closure_as_array_object->GetLength());
// The method has been successfully boxed into an object, now insert it into the hash map.
{
@@ -179,21 +134,24 @@
// we were allocating the object before.
ValueType value = FindBoxedLambda(closure);
if (UNLIKELY(!value.IsNull())) {
- // Let the GC clean up closure_as_object at a later time.
- // (We will not see this object when sweeping, it wasn't inserted yet.)
- closure_as_object->SetClosure(nullptr);
+ // Let the GC clean up method_as_object at a later time.
return value.Read();
}
// Otherwise we need to insert it into the hash map in this thread.
- // The closure_table_copy is deleted by us manually when we erase it from the map.
+ // Make a copy for the box table to keep, in case the closure gets collected from the stack.
+ // TODO: GC may need to sweep for roots in the box table's copy of the closure.
+ Closure* closure_table_copy = ClosureAllocator::Allocate(closure->GetSize());
+ closure->CopyTo(closure_table_copy, closure->GetSize());
+
+ // The closure_table_copy needs to be deleted by us manually when we erase it from the map.
// Actually insert into the table.
- map_.Insert({closure_table_copy.release(), ValueType(closure_as_object)});
+ map_.Insert({closure_table_copy, ValueType(closure_as_array_object)});
}
- return closure_as_object;
+ return closure_as_array_object;
}
bool BoxTable::UnboxLambda(mirror::Object* object, ClosureType* out_closure) {
@@ -207,35 +165,29 @@
mirror::Object* boxed_closure_object = object;
- // Raise ClassCastException if object is not instanceof LambdaProxy
- if (UNLIKELY(!boxed_closure_object->InstanceOf(GetBoxedClosureBaseClass()))) {
- ThrowClassCastException(GetBoxedClosureBaseClass(), boxed_closure_object->GetClass());
+ // Raise ClassCastException if object is not instanceof byte[]
+ if (UNLIKELY(!boxed_closure_object->InstanceOf(GetBoxedClosureClass()))) {
+ ThrowClassCastException(GetBoxedClosureClass(), boxed_closure_object->GetClass());
return false;
}
// TODO(iam): We must check that the closure object extends/implements the type
- // specified in [type id]. This is not currently implemented since the type id is unavailable.
+ // specified in [type id]. This is not currently implemented since it's always a byte[].
// If we got this far, the inputs are valid.
- // Shuffle the java.lang.LambdaProxy back into a raw closure, then allocate it, copy,
- // and return it.
- BoxedClosurePointerType boxed_closure =
+ // Shuffle the byte[] back into a raw closure, then allocate it, copy, and return it.
+ BoxedClosurePointerType boxed_closure_as_array =
down_cast<BoxedClosurePointerType>(boxed_closure_object);
- DCHECK_ALIGNED(boxed_closure->GetClosure(), alignof(Closure));
- const Closure* aligned_interior_closure = boxed_closure->GetClosure();
- DCHECK(aligned_interior_closure != nullptr);
-
- // TODO: we probably don't need to make a copy here later on, once there's GC support.
+ const int8_t* unaligned_interior_closure = boxed_closure_as_array->GetData();
// Allocate a copy that can "escape" and copy the closure data into that.
Closure* unboxed_closure =
- LeakingAllocator::MakeFlexibleInstance<Closure>(self, aligned_interior_closure->GetSize());
- DCHECK_ALIGNED(unboxed_closure, alignof(Closure));
+ LeakingAllocator::MakeFlexibleInstance<Closure>(self, boxed_closure_as_array->GetLength());
// TODO: don't just memcpy the closure, it's unsafe when we add references to the mix.
- memcpy(unboxed_closure, aligned_interior_closure, aligned_interior_closure->GetSize());
+ memcpy(unboxed_closure, unaligned_interior_closure, boxed_closure_as_array->GetLength());
- DCHECK_EQ(unboxed_closure->GetSize(), aligned_interior_closure->GetSize());
+ DCHECK_EQ(unboxed_closure->GetSize(), static_cast<size_t>(boxed_closure_as_array->GetLength()));
*out_closure = unboxed_closure;
return true;
@@ -284,10 +236,9 @@
if (new_value == nullptr) {
// The object has been swept away.
- Closure* closure = key_value_pair.first;
+ const ClosureType& closure = key_value_pair.first;
// Delete the entry from the map.
- // (Remove from map first to avoid accessing dangling pointer).
map_iterator = map_.Erase(map_iterator);
// Clean up the memory by deleting the closure.
@@ -339,10 +290,7 @@
}
bool BoxTable::EmptyFn::IsEmpty(const std::pair<UnorderedMapKeyType, ValueType>& item) const {
- bool is_empty = item.first == nullptr;
- DCHECK_EQ(item.second.IsNull(), is_empty);
-
- return is_empty;
+ return item.first == nullptr;
}
bool BoxTable::EqualsFn::operator()(const UnorderedMapKeyType& lhs,
diff --git a/runtime/lambda/box_table.h b/runtime/lambda/box_table.h
index 9dca6ab..adb7332 100644
--- a/runtime/lambda/box_table.h
+++ b/runtime/lambda/box_table.h
@@ -30,9 +30,6 @@
class ArtMethod; // forward declaration
namespace mirror {
-class Class; // forward declaration
-class ClassLoader; // forward declaration
-class LambdaProxy; // forward declaration
class Object; // forward declaration
} // namespace mirror
@@ -51,11 +48,8 @@
using ClosureType = art::lambda::Closure*;
// Boxes a closure into an object. Returns null and throws an exception on failure.
- mirror::Object* BoxLambda(const ClosureType& closure,
- const char* class_name,
- mirror::ClassLoader* class_loader)
- REQUIRES(!Locks::lambda_table_lock_, !Roles::uninterruptible_)
- SHARED_REQUIRES(Locks::mutator_lock_);
+ mirror::Object* BoxLambda(const ClosureType& closure)
+ SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!Locks::lambda_table_lock_);
// Unboxes an object back into the lambda. Returns false and throws an exception on failure.
bool UnboxLambda(mirror::Object* object, ClosureType* out_closure)
@@ -134,16 +128,7 @@
TrackingAllocator<std::pair<ClosureType, ValueType>,
kAllocatorTagLambdaBoxTable>>;
- using ClassMap = art::HashMap<std::string,
- GcRoot<mirror::Class>,
- EmptyFn,
- HashFn,
- EqualsFn,
- TrackingAllocator<std::pair<ClosureType, ValueType>,
- kAllocatorTagLambdaProxyClassBoxTable>>;
-
UnorderedMap map_ GUARDED_BY(Locks::lambda_table_lock_);
- UnorderedMap classes_map_ GUARDED_BY(Locks::lambda_table_lock_);
bool allow_new_weaks_ GUARDED_BY(Locks::lambda_table_lock_);
ConditionVariable new_weaks_condition_ GUARDED_BY(Locks::lambda_table_lock_);
diff --git a/runtime/lambda/closure.cc b/runtime/lambda/closure.cc
index f935e04..179e4ee 100644
--- a/runtime/lambda/closure.cc
+++ b/runtime/lambda/closure.cc
@@ -20,6 +20,9 @@
#include "lambda/art_lambda_method.h"
#include "runtime/mirror/object_reference.h"
+static constexpr const bool kClosureSupportsReferences = false;
+static constexpr const bool kClosureSupportsGarbageCollection = false;
+
namespace art {
namespace lambda {
@@ -125,10 +128,6 @@
return const_cast<ArtMethod*>(lambda_info_->GetArtMethod());
}
-ArtLambdaMethod* Closure::GetLambdaInfo() const {
- return const_cast<ArtLambdaMethod*>(lambda_info_);
-}
-
uint32_t Closure::GetHashCode() const {
// Start with a non-zero constant, a prime number.
uint32_t result = 17;
diff --git a/runtime/lambda/closure.h b/runtime/lambda/closure.h
index 38ec063..31ff194 100644
--- a/runtime/lambda/closure.h
+++ b/runtime/lambda/closure.h
@@ -33,52 +33,12 @@
class ArtLambdaMethod; // forward declaration
class ClosureBuilder; // forward declaration
-// TODO: Remove these constants once closures are supported properly.
-
-// Does the lambda closure support containing references? If so, all the users of lambdas
-// must be updated to also support references.
-static constexpr const bool kClosureSupportsReferences = false;
-// Does the lambda closure support being garbage collected? If so, all the users of lambdas
-// must be updated to also support garbage collection.
-static constexpr const bool kClosureSupportsGarbageCollection = false;
-// Does the lambda closure support being garbage collected with a read barrier? If so,
-// all the users of the lambdas msut also be updated to support read barrier GC.
-static constexpr const bool kClosureSupportsReadBarrier = false;
-
-// Is this closure being stored as a 'long' in shadow frames and the quick ABI?
-static constexpr const bool kClosureIsStoredAsLong = true;
-
-
-// Raw memory layout for the lambda closure.
-//
-// WARNING:
-// * This should only be used by the compiler and tests, as they need to offsetof the raw fields.
-// * Runtime/interpreter should always access closures through a Closure pointer.
-struct ClosureStorage {
- // Compile-time known lambda information such as the type descriptor and size.
- ArtLambdaMethod* lambda_info_;
-
- // A contiguous list of captured variables, and possibly the closure size.
- // The runtime size can always be determined through GetSize().
- union {
- // Read from here if the closure size is static (ArtLambdaMethod::IsStatic)
- uint8_t static_variables_[0];
- struct {
- // Read from here if the closure size is dynamic (ArtLambdaMethod::IsDynamic)
- size_t size_; // The lambda_info_ and the size_ itself is also included as part of the size.
- uint8_t variables_[0];
- } dynamic_;
- } captured_[0];
- // captured_ will always consist of one array element at runtime.
- // Set to [0] so that 'size_' is not counted in sizeof(Closure).
-};
-
// Inline representation of a lambda closure.
// Contains the target method and the set of packed captured variables as a copy.
//
// The closure itself is logically immutable, although in practice any object references
// it (recursively) contains can be moved and updated by the GC.
-struct Closure : private ClosureStorage {
+struct PACKED(sizeof(ArtLambdaMethod*)) Closure {
// Get the size of the Closure in bytes.
// This is necessary in order to allocate a large enough area to copy the Closure into.
// Do *not* copy the closure with memcpy, since references also need to get moved.
@@ -92,9 +52,6 @@
// Get the target method, i.e. the method that will be dispatched into with invoke-lambda.
ArtMethod* GetTargetMethod() const;
- // Get the static lambda info that never changes.
- ArtLambdaMethod* GetLambdaInfo() const;
-
// Calculates the hash code. Value is recomputed each time.
uint32_t GetHashCode() const SHARED_REQUIRES(Locks::mutator_lock_);
@@ -199,15 +156,28 @@
static size_t GetClosureSize(const uint8_t* closure);
///////////////////////////////////////////////////////////////////////////////////
- // NOTE: Actual fields are declared in ClosureStorage.
+
+ // Compile-time known lambda information such as the type descriptor and size.
+ ArtLambdaMethod* lambda_info_;
+
+ // A contiguous list of captured variables, and possibly the closure size.
+ // The runtime size can always be determined through GetSize().
+ union {
+ // Read from here if the closure size is static (ArtLambdaMethod::IsStatic)
+ uint8_t static_variables_[0];
+ struct {
+ // Read from here if the closure size is dynamic (ArtLambdaMethod::IsDynamic)
+ size_t size_; // The lambda_info_ and the size_ itself is also included as part of the size.
+ uint8_t variables_[0];
+ } dynamic_;
+ } captured_[0];
+ // captured_ will always consist of one array element at runtime.
+ // Set to [0] so that 'size_' is not counted in sizeof(Closure).
+
+ friend class ClosureBuilder;
friend class ClosureTest;
};
-// ABI guarantees:
-// * Closure same size as a ClosureStorage
-// * ClosureStorage begins at the same point a Closure would begin.
-static_assert(sizeof(Closure) == sizeof(ClosureStorage), "Closure size must match ClosureStorage");
-
} // namespace lambda
} // namespace art
diff --git a/runtime/lambda/closure_builder.cc b/runtime/lambda/closure_builder.cc
index 7b36042..739e965 100644
--- a/runtime/lambda/closure_builder.cc
+++ b/runtime/lambda/closure_builder.cc
@@ -75,7 +75,7 @@
if (LIKELY(is_dynamic_size_ == false)) {
// Write in the extra bytes to store the dynamic size the first time.
is_dynamic_size_ = true;
- size_ += sizeof(ClosureStorage::captured_[0].dynamic_.size_);
+ size_ += sizeof(Closure::captured_[0].dynamic_.size_);
}
// A closure may be sized dynamically, so always query it for the true size.
@@ -107,40 +107,38 @@
<< "number of variables captured at runtime does not match "
<< "number of variables captured at compile time";
- ClosureStorage* closure_storage = new (memory) ClosureStorage;
- closure_storage->lambda_info_ = target_method;
+ Closure* closure = new (memory) Closure;
+ closure->lambda_info_ = target_method;
- static_assert(offsetof(ClosureStorage, captured_) == kInitialSize, "wrong initial size");
+ static_assert(offsetof(Closure, captured_) == kInitialSize, "wrong initial size");
size_t written_size;
if (UNLIKELY(is_dynamic_size_)) {
// The closure size must be set dynamically (i.e. nested lambdas).
- closure_storage->captured_[0].dynamic_.size_ = GetSize();
- size_t header_size = offsetof(ClosureStorage, captured_[0].dynamic_.variables_);
+ closure->captured_[0].dynamic_.size_ = GetSize();
+ size_t header_size = offsetof(Closure, captured_[0].dynamic_.variables_);
DCHECK_LE(header_size, GetSize());
size_t variables_size = GetSize() - header_size;
written_size =
WriteValues(target_method,
- closure_storage->captured_[0].dynamic_.variables_,
+ closure->captured_[0].dynamic_.variables_,
header_size,
variables_size);
} else {
// The closure size is known statically (i.e. no nested lambdas).
DCHECK(GetSize() == target_method->GetStaticClosureSize());
- size_t header_size = offsetof(ClosureStorage, captured_[0].static_variables_);
+ size_t header_size = offsetof(Closure, captured_[0].static_variables_);
DCHECK_LE(header_size, GetSize());
size_t variables_size = GetSize() - header_size;
written_size =
WriteValues(target_method,
- closure_storage->captured_[0].static_variables_,
+ closure->captured_[0].static_variables_,
header_size,
variables_size);
}
- // OK: The closure storage is guaranteed to be the same as a closure.
- Closure* closure = reinterpret_cast<Closure*>(closure_storage);
-
DCHECK_EQ(written_size, closure->GetSize());
+
return closure;
}
diff --git a/runtime/lambda/shorty_field_type.h b/runtime/lambda/shorty_field_type.h
index 54bb4d4..46ddaa9 100644
--- a/runtime/lambda/shorty_field_type.h
+++ b/runtime/lambda/shorty_field_type.h
@@ -285,39 +285,6 @@
}
}
- // Get the number of virtual registers necessary to represent this type as a stack local.
- inline size_t GetVirtualRegisterCount() const {
- if (IsPrimitiveNarrow()) {
- return 1;
- } else if (IsPrimitiveWide()) {
- return 2;
- } else if (IsObject()) {
- return kObjectReferenceSize / sizeof(uint32_t);
- } else if (IsLambda()) {
- return 2;
- } else {
- DCHECK(false) << "unknown shorty field type '" << static_cast<char>(value_) << "'";
- UNREACHABLE();
- }
- }
-
- // Count how many virtual registers would be necessary in order to store this list of shorty
- // field types.
- inline size_t static CountVirtualRegistersRequired(const char* shorty) {
- size_t size = 0;
-
- while (shorty != nullptr && *shorty != '\0') {
- // Each argument appends to the size.
- ShortyFieldType shorty_field{*shorty}; // NOLINT [readability/braces] [4]
-
- size += shorty_field.GetVirtualRegisterCount();
-
- ++shorty;
- }
-
- return size;
- }
-
// Implicitly convert to the anonymous nested inner type. Used for exhaustive switch detection.
inline operator decltype(kByte)() const {
return value_;
diff --git a/runtime/lambda/shorty_field_type_test.cc b/runtime/lambda/shorty_field_type_test.cc
index 430e39e..32bade9 100644
--- a/runtime/lambda/shorty_field_type_test.cc
+++ b/runtime/lambda/shorty_field_type_test.cc
@@ -218,56 +218,6 @@
}
} // TEST_F
-TEST_F(ShortyFieldTypeTest, TestCalculateVRegSize) {
- // Make sure the single calculation for each value is correct.
- std::pair<size_t, char> expected_actual_single[] = {
- // Primitives
- { 1u, 'Z' },
- { 1u, 'B' },
- { 1u, 'C' },
- { 1u, 'S' },
- { 1u, 'I' },
- { 1u, 'F' },
- { 2u, 'J' },
- { 2u, 'D' },
- // Non-primitives
- { 1u, 'L' },
- { 2u, '\\' },
- };
-
- for (auto pair : expected_actual_single) {
- SCOPED_TRACE(pair.second);
- EXPECT_EQ(pair.first, ShortyFieldType(pair.second).GetVirtualRegisterCount());
- }
-
- // Make sure we are correctly calculating how many virtual registers a shorty descriptor takes.
- std::pair<size_t, const char*> expected_actual[] = {
- // Empty list
- { 0u, "" },
- // Primitives
- { 1u, "Z" },
- { 1u, "B" },
- { 1u, "C" },
- { 1u, "S" },
- { 1u, "I" },
- { 1u, "F" },
- { 2u, "J" },
- { 2u, "D" },
- // Non-primitives
- { 1u, "L" },
- { 2u, "\\" },
- // Multiple things at once:
- { 10u, "ZBCSIFJD" },
- { 5u, "LLSSI" },
- { 6u, "LLL\\L" }
- };
-
- for (auto pair : expected_actual) {
- SCOPED_TRACE(pair.second);
- EXPECT_EQ(pair.first, ShortyFieldType::CountVirtualRegistersRequired(pair.second));
- }
-} // TEST_F
-
// Helper class to probe a shorty's characteristics by minimizing copy-and-paste tests.
template <typename T, decltype(ShortyFieldType::kByte) kShortyEnum>
struct ShortyTypeCharacteristics {
diff --git a/runtime/lambda_proxy_test.cc b/runtime/lambda_proxy_test.cc
deleted file mode 100644
index 63d6ccc..0000000
--- a/runtime/lambda_proxy_test.cc
+++ /dev/null
@@ -1,367 +0,0 @@
-/*
- * 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 <jni.h>
-#include <vector>
-
-#include "art_field-inl.h"
-#include "class_linker-inl.h"
-#include "compiler_callbacks.h"
-#include "common_compiler_test.h"
-#include "mirror/field-inl.h"
-#include "mirror/lambda_proxy.h"
-#include "mirror/method.h"
-#include "scoped_thread_state_change.h"
-
-namespace art {
-
-// The enclosing class of all the interfaces used by this test.
-// -- Defined as a macro to allow for string concatenation.
-#define TEST_INTERFACE_ENCLOSING_CLASS_NAME "LambdaInterfaces"
-// Generate out "LLambdaInterfaces$<<iface>>;" , replacing <<iface>> with the interface name.
-#define MAKE_TEST_INTERFACE_NAME(iface) ("L" TEST_INTERFACE_ENCLOSING_CLASS_NAME "$" iface ";")
-
-#define ASSERT_NOT_NULL(x) ASSERT_TRUE((x) != nullptr)
-#define ASSERT_NULL(x) ASSERT_TRUE((x) == nullptr)
-#define EXPECT_NULL(x) EXPECT_TRUE((x) == nullptr)
-
-class LambdaProxyTest // : public CommonCompilerTest {
- : public CommonRuntimeTest {
- public:
- // Generate a lambda proxy class with the given name and interfaces. This is a simplification from what
- // libcore does to fit to our test needs. We do not check for duplicated interfaces or methods and
- // we do not declare exceptions.
- mirror::Class* GenerateProxyClass(ScopedObjectAccess& soa,
- jobject jclass_loader,
- const char* class_name,
- const std::vector<mirror::Class*>& interfaces)
- SHARED_REQUIRES(Locks::mutator_lock_) {
- CHECK(class_name != nullptr);
- CHECK(jclass_loader != nullptr);
-
- mirror::Class* java_lang_object =
- class_linker_->FindSystemClass(soa.Self(), "Ljava/lang/Object;");
- CHECK(java_lang_object != nullptr);
-
- jclass java_lang_class = soa.AddLocalReference<jclass>(mirror::Class::GetJavaLangClass());
-
- // Builds the interfaces array.
- jobjectArray proxy_class_interfaces = soa.Env()->NewObjectArray(interfaces.size(),
- java_lang_class,
- nullptr); // No initial element.
- soa.Self()->AssertNoPendingException();
- for (size_t i = 0; i < interfaces.size(); ++i) {
- soa.Env()->SetObjectArrayElement(proxy_class_interfaces,
- i,
- soa.AddLocalReference<jclass>(interfaces[i]));
- }
-
- // Builds the method array.
- jsize methods_count = 3; // Object.equals, Object.hashCode and Object.toString.
- for (mirror::Class* interface : interfaces) {
- methods_count += interface->NumVirtualMethods();
- }
- jobjectArray proxy_class_methods =
- soa.Env()->NewObjectArray(methods_count,
- soa.AddLocalReference<jclass>(mirror::Method::StaticClass()),
- nullptr); // No initial element.
- soa.Self()->AssertNoPendingException();
-
- jsize array_index = 0;
-
- //
- // Fill the method array with the Object and all the interface's virtual methods.
- //
-
- // Add a method to 'proxy_class_methods'
- auto add_method_to_array = [&](ArtMethod* method) SHARED_REQUIRES(Locks::mutator_lock_) {
- CHECK(method != nullptr);
- soa.Env()->SetObjectArrayElement(proxy_class_methods,
- array_index++,
- soa.AddLocalReference<jobject>(
- mirror::Method::CreateFromArtMethod(soa.Self(),
- method))
- ); // NOLINT: [whitespace/parens] [2]
-
- LOG(DEBUG) << "Add " << PrettyMethod(method) << " to list of methods to generate proxy";
- };
- // Add a method to 'proxy_class_methods' by looking it up from java.lang.Object
- auto add_method_to_array_by_lookup = [&](const char* name, const char* method_descriptor)
- SHARED_REQUIRES(Locks::mutator_lock_) {
- ArtMethod* method = java_lang_object->FindDeclaredVirtualMethod(name,
- method_descriptor,
- sizeof(void*));
- add_method_to_array(method);
- };
-
- // Add all methods from Object.
- add_method_to_array_by_lookup("equals", "(Ljava/lang/Object;)Z");
- add_method_to_array_by_lookup("hashCode", "()I");
- add_method_to_array_by_lookup("toString", "()Ljava/lang/String;");
-
- // Now adds all interfaces virtual methods.
- for (mirror::Class* interface : interfaces) {
- mirror::Class* next_class = interface;
- do {
- for (ArtMethod& method : next_class->GetVirtualMethods(sizeof(void*))) {
- add_method_to_array(&method);
- }
- next_class = next_class->GetSuperClass();
- } while (!next_class->IsObjectClass());
- // Skip adding any methods from "Object".
- }
- CHECK_EQ(array_index, methods_count);
-
- // Builds an empty exception array.
- jobjectArray proxy_class_throws = soa.Env()->NewObjectArray(0 /* length */,
- java_lang_class,
- nullptr /* initial element*/);
- soa.Self()->AssertNoPendingException();
-
- bool already_exists;
- mirror::Class* proxy_class =
- class_linker_->CreateLambdaProxyClass(soa,
- soa.Env()->NewStringUTF(class_name),
- proxy_class_interfaces,
- jclass_loader,
- proxy_class_methods,
- proxy_class_throws,
- /*out*/&already_exists);
-
- CHECK(!already_exists);
-
- soa.Self()->AssertNoPendingException();
- return proxy_class;
- }
-
- LambdaProxyTest() {
- }
-
- virtual void SetUp() {
- CommonRuntimeTest::SetUp();
- }
-
- virtual void SetUpRuntimeOptions(RuntimeOptions* options ATTRIBUTE_UNUSED) {
- // Do not have any compiler options because we don't want to run as an AOT
- // (In particular the lambda proxy class generation isn't currently supported for AOT).
- this->callbacks_.reset();
- }
-
- template <typename THandleScope>
- Handle<mirror::Class> GenerateProxyClass(THandleScope& hs,
- const char* name,
- const std::vector<mirror::Class*>& interfaces)
- SHARED_REQUIRES(Locks::mutator_lock_) {
- return hs.NewHandle(GenerateProxyClass(*soa_, jclass_loader_, name, interfaces));
- }
-
- protected:
- ScopedObjectAccess* soa_ = nullptr;
- jobject jclass_loader_ = nullptr;
-};
-
-// Creates a lambda proxy class and check ClassHelper works correctly.
-TEST_F(LambdaProxyTest, ProxyClassHelper) {
- // gLogVerbosity.class_linker = true; // Uncomment to enable class linker logging.
-
- ASSERT_NOT_NULL(Thread::Current());
-
- ScopedObjectAccess soa(Thread::Current());
- soa_ = &soa;
-
- // Must happen after CommonRuntimeTest finishes constructing the runtime.
- jclass_loader_ = LoadDex(TEST_INTERFACE_ENCLOSING_CLASS_NAME);
- jobject jclass_loader = jclass_loader_;
-
- StackHandleScope<4> hs(soa.Self());
- Handle<mirror::ClassLoader> class_loader(
- hs.NewHandle(soa.Decode<mirror::ClassLoader*>(jclass_loader)));
-
- Handle<mirror::Class> J(hs.NewHandle(
- class_linker_->FindClass(soa.Self(), MAKE_TEST_INTERFACE_NAME("J"), class_loader)));
- ASSERT_TRUE(J.Get() != nullptr);
-
- std::vector<mirror::Class*> interfaces;
- interfaces.push_back(J.Get());
- Handle<mirror::Class> proxy_class(hs.NewHandle(
- GenerateProxyClass(soa, jclass_loader, "$Proxy1234", interfaces)));
- interfaces.clear(); // Don't least possibly stale objects in the array as good practice.
- ASSERT_TRUE(proxy_class.Get() != nullptr);
- ASSERT_TRUE(proxy_class->IsLambdaProxyClass());
- ASSERT_TRUE(proxy_class->IsInitialized());
-
- EXPECT_EQ(1U, proxy_class->NumDirectInterfaces()); // LambdaInterfaces$J.
- EXPECT_EQ(J.Get(), mirror::Class::GetDirectInterface(soa.Self(), proxy_class, 0));
- std::string temp;
- const char* proxy_class_descriptor = proxy_class->GetDescriptor(&temp);
- EXPECT_STREQ("L$Proxy1234;", proxy_class_descriptor);
- EXPECT_EQ(nullptr, proxy_class->GetSourceFile());
-
- // Make sure all the virtual methods are marked as a proxy
- for (ArtMethod& method : proxy_class->GetVirtualMethods(sizeof(void*))) {
- SCOPED_TRACE(PrettyMethod(&method, /* with_signature */true));
- EXPECT_TRUE(method.IsProxyMethod());
- EXPECT_TRUE(method.IsLambdaProxyMethod());
- EXPECT_FALSE(method.IsReflectProxyMethod());
- }
-}
-
-// Creates a proxy class and check FieldHelper works correctly.
-TEST_F(LambdaProxyTest, ProxyFieldHelper) {
- // gLogVerbosity.class_linker = true; // Uncomment to enable class linker logging.
-
- ASSERT_NOT_NULL(Thread::Current());
-
- ScopedObjectAccess soa(Thread::Current());
- soa_ = &soa;
-
- // Must happen after CommonRuntimeTest finishes constructing the runtime.
- jclass_loader_ = LoadDex(TEST_INTERFACE_ENCLOSING_CLASS_NAME);
- jobject jclass_loader = jclass_loader_;
-
- StackHandleScope<9> hs(soa.Self());
- Handle<mirror::ClassLoader> class_loader(
- hs.NewHandle(soa.Decode<mirror::ClassLoader*>(jclass_loader)));
-
- Handle<mirror::Class> I(hs.NewHandle(
- class_linker_->FindClass(soa.Self(), MAKE_TEST_INTERFACE_NAME("I"), class_loader)));
- ASSERT_NOT_NULL(I.Get());
-
- // Create the lambda proxy which implements interfaces "I".
- Handle<mirror::Class> proxy_class = GenerateProxyClass(hs,
- "$Proxy1234",
- { I.Get() }); // Interfaces.
-
- ASSERT_NOT_NULL(proxy_class.Get());
- EXPECT_TRUE(proxy_class->IsLambdaProxyClass());
- EXPECT_TRUE(proxy_class->IsInitialized());
- EXPECT_NULL(proxy_class->GetIFieldsPtr());
-
- LengthPrefixedArray<ArtField>* static_fields = proxy_class->GetSFieldsPtr();
- ASSERT_NOT_NULL(static_fields);
-
- // Must have "throws" and "interfaces" static fields.
- ASSERT_EQ(+mirror::LambdaProxy::kStaticFieldCount, proxy_class->NumStaticFields());
-
- static constexpr const char* kInterfacesClassName = "[Ljava/lang/Class;";
- static constexpr const char* kThrowsClassName = "[[Ljava/lang/Class;";
-
- // Class for "interfaces" field.
- Handle<mirror::Class> interfaces_field_class =
- hs.NewHandle(class_linker_->FindSystemClass(soa.Self(), kInterfacesClassName));
- ASSERT_NOT_NULL(interfaces_field_class.Get());
-
- // Class for "throws" field.
- Handle<mirror::Class> throws_field_class =
- hs.NewHandle(class_linker_->FindSystemClass(soa.Self(), kThrowsClassName));
- ASSERT_NOT_NULL(throws_field_class.Get());
-
- // Helper to test the static fields for correctness.
- auto test_static_field = [&](size_t index,
- const char* field_name,
- Handle<mirror::Class>& handle_class,
- const char* class_name)
- SHARED_REQUIRES(Locks::mutator_lock_) {
- ArtField* field = &static_fields->At(index);
- EXPECT_STREQ(field_name, field->GetName());
- EXPECT_STREQ(class_name, field->GetTypeDescriptor());
- EXPECT_EQ(handle_class.Get(), field->GetType</*kResolve*/true>())
- << "Expected: " << PrettyClass(interfaces_field_class.Get()) << ", "
- << "Actual: " << PrettyClass(field->GetType</*kResolve*/true>()) << ", "
- << "field_name: " << field_name;
- std::string temp;
- EXPECT_STREQ("L$Proxy1234;", field->GetDeclaringClass()->GetDescriptor(&temp));
- EXPECT_FALSE(field->IsPrimitiveType());
- };
-
- // Test "Class[] interfaces" field.
- test_static_field(mirror::LambdaProxy::kStaticFieldIndexInterfaces,
- "interfaces",
- interfaces_field_class,
- kInterfacesClassName);
-
- // Test "Class[][] throws" field.
- test_static_field(mirror::LambdaProxy::kStaticFieldIndexThrows,
- "throws",
- throws_field_class,
- kThrowsClassName);
-}
-
-// Creates two proxy classes and check the art/mirror fields of their static fields.
-TEST_F(LambdaProxyTest, CheckArtMirrorFieldsOfProxyStaticFields) {
- // gLogVerbosity.class_linker = true; // Uncomment to enable class linker logging.
-
- ASSERT_NOT_NULL(Thread::Current());
-
- ScopedObjectAccess soa(Thread::Current());
- soa_ = &soa;
-
- // Must happen after CommonRuntimeTest finishes constructing the runtime.
- jclass_loader_ = LoadDex(TEST_INTERFACE_ENCLOSING_CLASS_NAME);
- jobject jclass_loader = jclass_loader_;
-
- StackHandleScope<8> hs(soa.Self());
- Handle<mirror::ClassLoader> class_loader(
- hs.NewHandle(soa.Decode<mirror::ClassLoader*>(jclass_loader)));
-
- Handle<mirror::Class> proxyClass0;
- Handle<mirror::Class> proxyClass1;
- {
- Handle<mirror::Class> L(hs.NewHandle(
- class_linker_->FindClass(soa.Self(), MAKE_TEST_INTERFACE_NAME("L"), class_loader)));
- ASSERT_TRUE(L.Get() != nullptr);
-
- std::vector<mirror::Class*> interfaces = { L.Get() };
- proxyClass0 = hs.NewHandle(GenerateProxyClass(soa, jclass_loader, "$Proxy0", interfaces));
- proxyClass1 = hs.NewHandle(GenerateProxyClass(soa, jclass_loader, "$Proxy1", interfaces));
- }
-
- ASSERT_TRUE(proxyClass0.Get() != nullptr);
- ASSERT_TRUE(proxyClass0->IsLambdaProxyClass());
- ASSERT_TRUE(proxyClass0->IsInitialized());
- ASSERT_TRUE(proxyClass1.Get() != nullptr);
- ASSERT_TRUE(proxyClass1->IsLambdaProxyClass());
- ASSERT_TRUE(proxyClass1->IsInitialized());
-
- LengthPrefixedArray<ArtField>* static_fields0 = proxyClass0->GetSFieldsPtr();
- ASSERT_TRUE(static_fields0 != nullptr);
- ASSERT_EQ(2u, static_fields0->size());
- LengthPrefixedArray<ArtField>* static_fields1 = proxyClass1->GetSFieldsPtr();
- ASSERT_TRUE(static_fields1 != nullptr);
- ASSERT_EQ(2u, static_fields1->size());
-
- EXPECT_EQ(static_fields0->At(0).GetDeclaringClass(), proxyClass0.Get());
- EXPECT_EQ(static_fields0->At(1).GetDeclaringClass(), proxyClass0.Get());
- EXPECT_EQ(static_fields1->At(0).GetDeclaringClass(), proxyClass1.Get());
- EXPECT_EQ(static_fields1->At(1).GetDeclaringClass(), proxyClass1.Get());
-
- Handle<mirror::Field> field00 =
- hs.NewHandle(mirror::Field::CreateFromArtField(soa.Self(), &static_fields0->At(0), true));
- Handle<mirror::Field> field01 =
- hs.NewHandle(mirror::Field::CreateFromArtField(soa.Self(), &static_fields0->At(1), true));
- Handle<mirror::Field> field10 =
- hs.NewHandle(mirror::Field::CreateFromArtField(soa.Self(), &static_fields1->At(0), true));
- Handle<mirror::Field> field11 =
- hs.NewHandle(mirror::Field::CreateFromArtField(soa.Self(), &static_fields1->At(1), true));
- EXPECT_EQ(field00->GetArtField(), &static_fields0->At(0));
- EXPECT_EQ(field01->GetArtField(), &static_fields0->At(1));
- EXPECT_EQ(field10->GetArtField(), &static_fields1->At(0));
- EXPECT_EQ(field11->GetArtField(), &static_fields1->At(1));
-}
-
-// TODO: make sure there's a non-abstract implementation of the single-abstract-method on the class.
-
-} // namespace art
diff --git a/runtime/mirror/class-inl.h b/runtime/mirror/class-inl.h
index a8685b8..9e416dc 100644
--- a/runtime/mirror/class-inl.h
+++ b/runtime/mirror/class-inl.h
@@ -695,11 +695,7 @@
}
inline const DexFile& Class::GetDexFile() {
- DexCache* dex_cache = GetDexCache();
- DCHECK(dex_cache != nullptr);
- const DexFile* dex_file = dex_cache->GetDexFile();
- DCHECK(dex_file != nullptr);
- return *dex_file;
+ return *GetDexCache()->GetDexFile();
}
inline bool Class::DescriptorEquals(const char* match) {
@@ -707,8 +703,8 @@
return match[0] == '[' && GetComponentType()->DescriptorEquals(match + 1);
} else if (IsPrimitive()) {
return strcmp(Primitive::Descriptor(GetPrimitiveType()), match) == 0;
- } else if (IsAnyProxyClass()) {
- return AnyProxyDescriptorEquals(match);
+ } else if (IsProxyClass()) {
+ return ProxyDescriptorEquals(match);
} else {
const DexFile& dex_file = GetDexFile();
const DexFile::TypeId& type_id = dex_file.GetTypeId(GetClassDef()->class_idx_);
@@ -724,32 +720,22 @@
}
}
-inline ObjectArray<Class>* Class::GetInterfacesForAnyProxy() {
- CHECK(IsAnyProxyClass());
+inline ObjectArray<Class>* Class::GetInterfaces() {
+ CHECK(IsProxyClass());
// First static field.
auto* field = GetStaticField(0);
DCHECK_STREQ(field->GetName(), "interfaces");
MemberOffset field_offset = field->GetOffset();
- ObjectArray<Class>* interfaces_array = GetFieldObject<ObjectArray<Class>>(field_offset);
-
- CHECK(interfaces_array != nullptr);
- if (UNLIKELY(IsLambdaProxyClass())) {
- DCHECK_EQ(1, interfaces_array->GetLength())
- << "Lambda proxies cannot have multiple direct interfaces implemented";
- }
- return interfaces_array;
+ return GetFieldObject<ObjectArray<Class>>(field_offset);
}
-inline ObjectArray<ObjectArray<Class>>* Class::GetThrowsForAnyProxy() {
- CHECK(IsAnyProxyClass());
+inline ObjectArray<ObjectArray<Class>>* Class::GetThrows() {
+ CHECK(IsProxyClass());
// Second static field.
auto* field = GetStaticField(1);
DCHECK_STREQ(field->GetName(), "throws");
-
MemberOffset field_offset = field->GetOffset();
- auto* throws_array = GetFieldObject<ObjectArray<ObjectArray<Class>>>(field_offset);
- CHECK(throws_array != nullptr);
- return throws_array;
+ return GetFieldObject<ObjectArray<ObjectArray<Class>>>(field_offset);
}
inline MemberOffset Class::GetDisableIntrinsicFlagOffset() {
@@ -810,8 +796,8 @@
return 0;
} else if (IsArrayClass()) {
return 2;
- } else if (IsAnyProxyClass()) {
- mirror::ObjectArray<mirror::Class>* interfaces = GetInterfacesForAnyProxy();
+ } else if (IsProxyClass()) {
+ mirror::ObjectArray<mirror::Class>* interfaces = GetInterfaces();
return interfaces != nullptr ? interfaces->GetLength() : 0;
} else {
const DexFile::TypeList* interfaces = GetInterfaceTypeList();
diff --git a/runtime/mirror/class.cc b/runtime/mirror/class.cc
index b201293..05a9039 100644
--- a/runtime/mirror/class.cc
+++ b/runtime/mirror/class.cc
@@ -538,7 +538,6 @@
ArtMethod* Class::FindClassInitializer(size_t pointer_size) {
for (ArtMethod& method : GetDirectMethods(pointer_size)) {
- DCHECK(reinterpret_cast<volatile void*>(&method) != nullptr);
if (method.IsClassInitializer()) {
DCHECK_STREQ(method.GetName(), "<clinit>");
DCHECK_STREQ(method.GetSignature().ToString().c_str(), "()V");
@@ -743,8 +742,8 @@
return Primitive::Descriptor(GetPrimitiveType());
} else if (IsArrayClass()) {
return GetArrayDescriptor(storage);
- } else if (IsAnyProxyClass()) {
- *storage = Runtime::Current()->GetClassLinker()->GetDescriptorForAnyProxy(this);
+ } else if (IsProxyClass()) {
+ *storage = Runtime::Current()->GetClassLinker()->GetDescriptorForProxy(this);
return storage->c_str();
} else {
const DexFile& dex_file = GetDexFile();
@@ -787,10 +786,8 @@
DCHECK_EQ(1U, idx);
return class_linker->FindSystemClass(self, "Ljava/io/Serializable;");
}
- } else if (klass->IsAnyProxyClass()) {
- // Proxies don't have a dex cache, so look at the
- // interfaces through the magic static field "interfaces" from the proxy class itself.
- mirror::ObjectArray<mirror::Class>* interfaces = klass.Get()->GetInterfacesForAnyProxy();
+ } else if (klass->IsProxyClass()) {
+ mirror::ObjectArray<mirror::Class>* interfaces = klass.Get()->GetInterfaces();
DCHECK(interfaces != nullptr);
return interfaces->Get(idx);
} else {
@@ -829,7 +826,7 @@
std::string Class::GetLocation() {
mirror::DexCache* dex_cache = GetDexCache();
- if (dex_cache != nullptr && !IsAnyProxyClass()) {
+ if (dex_cache != nullptr && !IsProxyClass()) {
return dex_cache->GetLocation()->ToModifiedUtf8();
}
// Arrays and proxies are generated and have no corresponding dex file location.
@@ -947,9 +944,9 @@
return new_class->AsClass();
}
-bool Class::AnyProxyDescriptorEquals(const char* match) {
- DCHECK(IsAnyProxyClass());
- return Runtime::Current()->GetClassLinker()->GetDescriptorForAnyProxy(this) == match;
+bool Class::ProxyDescriptorEquals(const char* match) {
+ DCHECK(IsProxyClass());
+ return Runtime::Current()->GetClassLinker()->GetDescriptorForProxy(this) == match;
}
// TODO: Move this to java_lang_Class.cc?
diff --git a/runtime/mirror/class.h b/runtime/mirror/class.h
index fcfb4b9..0ab5b97 100644
--- a/runtime/mirror/class.h
+++ b/runtime/mirror/class.h
@@ -352,16 +352,8 @@
static String* ComputeName(Handle<Class> h_this) SHARED_REQUIRES(Locks::mutator_lock_)
REQUIRES(!Roles::uninterruptible_);
- // Is this either a java.lang.reflect.Proxy or a boxed lambda (java.lang.LambdaProxy)?
- // -- Most code doesn't need to make the distinction, and this is the preferred thing to check.
template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
- bool IsAnyProxyClass() SHARED_REQUIRES(Locks::mutator_lock_) {
- return IsReflectProxyClass() || IsLambdaProxyClass();
- }
-
- // Is this a java.lang.reflect.Proxy ?
- template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
- bool IsReflectProxyClass() SHARED_REQUIRES(Locks::mutator_lock_) {
+ bool IsProxyClass() SHARED_REQUIRES(Locks::mutator_lock_) {
// Read access flags without using getter as whether something is a proxy can be check in
// any loaded state
// TODO: switch to a check if the super class is java.lang.reflect.Proxy?
@@ -369,17 +361,6 @@
return (access_flags & kAccClassIsProxy) != 0;
}
- // Is this a boxed lambda (java.lang.LambdaProxy)?
- template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
- bool IsLambdaProxyClass() SHARED_REQUIRES(Locks::mutator_lock_) {
- // Read access flags without using getter as whether something is a proxy can be check in
- // any loaded state
- // TODO: switch to a check if the super class is java.lang.reflect.Proxy?
- uint32_t access_flags = GetField32<kVerifyFlags>(OFFSET_OF_OBJECT_MEMBER(Class, access_flags_));
- return (access_flags & kAccClassIsLambdaProxy) != 0;
- }
-
-
static MemberOffset PrimitiveTypeOffset() {
return OFFSET_OF_OBJECT_MEMBER(Class, primitive_type_);
}
@@ -696,8 +677,6 @@
return MemberOffset(OFFSETOF_MEMBER(Class, super_class_));
}
- // Returns the class's ClassLoader.
- // A null value is returned if and only if this is a boot classpath class.
ClassLoader* GetClassLoader() ALWAYS_INLINE SHARED_REQUIRES(Locks::mutator_lock_);
void SetClassLoader(ClassLoader* new_cl) SHARED_REQUIRES(Locks::mutator_lock_);
@@ -1097,8 +1076,6 @@
bool DescriptorEquals(const char* match) SHARED_REQUIRES(Locks::mutator_lock_);
- // Returns the backing DexFile's class definition for this class.
- // This returns null if and only if the class has no backing DexFile.
const DexFile::ClassDef* GetClassDef() SHARED_REQUIRES(Locks::mutator_lock_);
ALWAYS_INLINE uint32_t NumDirectInterfaces() SHARED_REQUIRES(Locks::mutator_lock_);
@@ -1125,15 +1102,11 @@
size_t pointer_size)
SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_);
- // For any proxy class only. Returns list of directly implemented interfaces.
- // The value returned is always non-null.
- ObjectArray<Class>* GetInterfacesForAnyProxy() SHARED_REQUIRES(Locks::mutator_lock_);
+ // For proxy class only.
+ ObjectArray<Class>* GetInterfaces() SHARED_REQUIRES(Locks::mutator_lock_);
- // For any proxy class only. Returns a 2d array of classes.
- // -- The 0th dimension correponds to the vtable index.
- // -- The 1st dimension is a list of checked exception classes.
- // The value returned is always non-null.
- ObjectArray<ObjectArray<Class>>* GetThrowsForAnyProxy() SHARED_REQUIRES(Locks::mutator_lock_);
+ // For proxy class only.
+ ObjectArray<ObjectArray<Class>>* GetThrows() SHARED_REQUIRES(Locks::mutator_lock_);
// For reference class only.
MemberOffset GetDisableIntrinsicFlagOffset() SHARED_REQUIRES(Locks::mutator_lock_);
@@ -1221,7 +1194,7 @@
IterationRange<StrideIterator<ArtField>> GetIFieldsUnchecked()
SHARED_REQUIRES(Locks::mutator_lock_);
- bool AnyProxyDescriptorEquals(const char* match) SHARED_REQUIRES(Locks::mutator_lock_);
+ bool ProxyDescriptorEquals(const char* match) SHARED_REQUIRES(Locks::mutator_lock_);
// Check that the pointer size matches the one in the class linker.
ALWAYS_INLINE static void CheckPointerSize(size_t pointer_size);
diff --git a/runtime/mirror/class_loader-inl.h b/runtime/mirror/class_loader-inl.h
index 3139117..e22ddd7 100644
--- a/runtime/mirror/class_loader-inl.h
+++ b/runtime/mirror/class_loader-inl.h
@@ -21,7 +21,6 @@
#include "base/mutex-inl.h"
#include "class_table-inl.h"
-#include "lambda/box_class_table-inl.h"
namespace art {
namespace mirror {
@@ -36,10 +35,6 @@
if (class_table != nullptr) {
class_table->VisitRoots(visitor);
}
- lambda::BoxClassTable* const lambda_box_class_table = GetLambdaProxyCache();
- if (lambda_box_class_table != nullptr) {
- lambda_box_class_table->VisitRoots(visitor);
- }
}
} // namespace mirror
diff --git a/runtime/mirror/class_loader.h b/runtime/mirror/class_loader.h
index 9d4fe96..c2a65d6 100644
--- a/runtime/mirror/class_loader.h
+++ b/runtime/mirror/class_loader.h
@@ -24,12 +24,6 @@
struct ClassLoaderOffsets;
class ClassTable;
-namespace lambda {
-
-class BoxClassTable;
-
-} // namespace lambda
-
namespace mirror {
class Class;
@@ -66,16 +60,6 @@
reinterpret_cast<uint64_t>(allocator));
}
- lambda::BoxClassTable* GetLambdaProxyCache() SHARED_REQUIRES(Locks::mutator_lock_) {
- return reinterpret_cast<lambda::BoxClassTable*>(
- GetField64(OFFSET_OF_OBJECT_MEMBER(ClassLoader, lambda_proxy_cache_)));
- }
-
- void SetLambdaProxyCache(lambda::BoxClassTable* cache) SHARED_REQUIRES(Locks::mutator_lock_) {
- SetField64<false>(OFFSET_OF_OBJECT_MEMBER(ClassLoader, lambda_proxy_cache_),
- reinterpret_cast<uint64_t>(cache));
- }
-
private:
// Visit instance fields of the class loader as well as its associated classes.
// Null class loader is handled by ClassLinker::VisitClassRoots.
@@ -92,7 +76,6 @@
uint32_t padding_ ATTRIBUTE_UNUSED;
uint64_t allocator_;
uint64_t class_table_;
- uint64_t lambda_proxy_cache_;
friend struct art::ClassLoaderOffsets; // for verifying offset information
friend class Object; // For VisitReferences
diff --git a/runtime/mirror/field-inl.h b/runtime/mirror/field-inl.h
index 49c443e..8a0daec 100644
--- a/runtime/mirror/field-inl.h
+++ b/runtime/mirror/field-inl.h
@@ -57,15 +57,14 @@
const auto pointer_size = kTransactionActive ?
Runtime::Current()->GetClassLinker()->GetImagePointerSize() : sizeof(void*);
auto dex_field_index = field->GetDexFieldIndex();
- if (field->GetDeclaringClass()->IsAnyProxyClass()) {
+ auto* resolved_field = field->GetDexCache()->GetResolvedField(dex_field_index, pointer_size);
+ if (field->GetDeclaringClass()->IsProxyClass()) {
DCHECK(field->IsStatic());
DCHECK_LT(dex_field_index, 2U);
// The two static fields (interfaces, throws) of all proxy classes
// share the same dex file indices 0 and 1. So, we can't resolve
// them in the dex cache.
} else {
- ArtField* resolved_field =
- field->GetDexCache()->GetResolvedField(dex_field_index, pointer_size);
if (resolved_field != nullptr) {
DCHECK_EQ(resolved_field, field);
} else {
diff --git a/runtime/mirror/field.cc b/runtime/mirror/field.cc
index b02e5b5..ff6847c 100644
--- a/runtime/mirror/field.cc
+++ b/runtime/mirror/field.cc
@@ -56,7 +56,7 @@
ArtField* Field::GetArtField() {
mirror::Class* declaring_class = GetDeclaringClass();
- if (UNLIKELY(declaring_class->IsAnyProxyClass())) {
+ if (UNLIKELY(declaring_class->IsProxyClass())) {
DCHECK(IsStatic());
DCHECK_EQ(declaring_class->NumStaticFields(), 2U);
// 0 == Class[] interfaces; 1 == Class[][] throws;
diff --git a/runtime/mirror/lambda_proxy.h b/runtime/mirror/lambda_proxy.h
deleted file mode 100644
index cff3a12..0000000
--- a/runtime/mirror/lambda_proxy.h
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * 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_MIRROR_LAMBDA_PROXY_H_
-#define ART_RUNTIME_MIRROR_LAMBDA_PROXY_H_
-
-#include "lambda/closure.h"
-#include "object.h"
-
-namespace art {
-
-struct LambdaProxyOffsets;
-
-namespace mirror {
-
-// C++ mirror of a lambda proxy. Does not yet have a Java-equivalent source file.
-class MANAGED LambdaProxy FINAL : public Object {
- public:
- // Note that the runtime subclasses generate the following static fields:
-
- // private static java.lang.Class[] interfaces; // Declared interfaces for the lambda interface.
- static constexpr size_t kStaticFieldIndexInterfaces = 0;
- // private static java.lang.Class[][] throws; // Maps vtable id to list of classes.
- static constexpr size_t kStaticFieldIndexThrows = 1;
- static constexpr size_t kStaticFieldCount = 2; // Number of fields total.
-
- // The offset from the start of 'LambdaProxy' object, to the closure_ field, in bytes.
- // -- This is exposed publically in order to avoid exposing 'closure_' publically.
- // -- Only meant to be used in stubs and other compiled code, not in runtime.
- static inline MemberOffset GetInstanceFieldOffsetClosure() {
- return OFFSET_OF_OBJECT_MEMBER(LambdaProxy, closure_);
- }
-
- // Direct methods available on the class:
- static constexpr size_t kDirectMethodIndexConstructor = 0; // <init>()V
- static constexpr size_t kDirectMethodCount = 1; // Only the constructor.
-
- // Accessors to the fields:
-
- // Get the native closure pointer. Usually non-null outside of lambda proxy contexts.
- lambda::Closure* GetClosure() SHARED_REQUIRES(Locks::mutator_lock_) {
- return reinterpret_cast<lambda::Closure*>(
- GetField64(GetInstanceFieldOffsetClosure()));
- }
-
- // Set the native closure pointer. Usually should be non-null outside of lambda proxy contexts.
- void SetClosure(lambda::Closure* closure) SHARED_REQUIRES(Locks::mutator_lock_) {
- SetField64<false>(GetInstanceFieldOffsetClosure(),
- reinterpret_cast<uint64_t>(closure));
- }
-
- private:
- // Instance fields, present in the base class and every generated subclass:
-
- // private long closure;
- union {
- lambda::Closure* actual;
- uint64_t padding; // Don't trip up GetObjectSize checks, since the Java code has a long.
- } closure_;
-
- // Friends for generating offset tests:
- friend struct art::LambdaProxyOffsets; // for verifying offset information
-
- DISALLOW_IMPLICIT_CONSTRUCTORS(LambdaProxy);
-};
-
-} // namespace mirror
-} // namespace art
-
-#endif // ART_RUNTIME_MIRROR_LAMBDA_PROXY_H_
diff --git a/runtime/modifiers.h b/runtime/modifiers.h
index 36aa57f..9946eab 100644
--- a/runtime/modifiers.h
+++ b/runtime/modifiers.h
@@ -54,8 +54,6 @@
// if any particular method needs to be a default conflict. Used to figure out at runtime if
// invoking this method will throw an exception.
static constexpr uint32_t kAccDefaultConflict = 0x00800000; // method (runtime)
-// Set by the class linker when creating a class that's a subtype of LambdaProxy.
-static constexpr uint32_t kAccClassIsLambdaProxy = 0x01000000; // class (dex only)
// Special runtime-only flags.
// Interface and all its super-interfaces with default methods have been recursively initialized.
diff --git a/runtime/native/java_lang_Class.cc b/runtime/native/java_lang_Class.cc
index 6cebd4d..5e42392 100644
--- a/runtime/native/java_lang_Class.cc
+++ b/runtime/native/java_lang_Class.cc
@@ -103,7 +103,7 @@
static jobjectArray Class_getProxyInterfaces(JNIEnv* env, jobject javaThis) {
ScopedFastNativeObjectAccess soa(env);
mirror::Class* c = DecodeClass(soa, javaThis);
- return soa.AddLocalReference<jobjectArray>(c->GetInterfacesForAnyProxy()->Clone(soa.Self()));
+ return soa.AddLocalReference<jobjectArray>(c->GetInterfaces()->Clone(soa.Self()));
}
static mirror::ObjectArray<mirror::Field>* GetDeclaredFields(
@@ -489,7 +489,7 @@
ScopedFastNativeObjectAccess soa(env);
StackHandleScope<2> hs(soa.Self());
Handle<mirror::Class> klass(hs.NewHandle(DecodeClass(soa, javaThis)));
- if (klass->IsAnyProxyClass() || klass->GetDexCache() == nullptr) {
+ if (klass->IsProxyClass() || klass->GetDexCache() == nullptr) {
return nullptr;
}
Handle<mirror::Class> annotation_class(hs.NewHandle(soa.Decode<mirror::Class*>(annotationType)));
@@ -501,7 +501,7 @@
ScopedFastNativeObjectAccess soa(env);
StackHandleScope<1> hs(soa.Self());
Handle<mirror::Class> klass(hs.NewHandle(DecodeClass(soa, javaThis)));
- if (klass->IsAnyProxyClass() || klass->GetDexCache() == nullptr) {
+ if (klass->IsProxyClass() || klass->GetDexCache() == nullptr) {
// Return an empty array instead of a null pointer.
mirror::Class* annotation_array_class =
soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_annotation_Annotation__array);
@@ -517,7 +517,7 @@
StackHandleScope<1> hs(soa.Self());
Handle<mirror::Class> klass(hs.NewHandle(DecodeClass(soa, javaThis)));
mirror::ObjectArray<mirror::Class>* classes = nullptr;
- if (!klass->IsAnyProxyClass() && klass->GetDexCache() != nullptr) {
+ if (!klass->IsProxyClass() && klass->GetDexCache() != nullptr) {
classes = klass->GetDexFile().GetDeclaredClasses(klass);
}
if (classes == nullptr) {
@@ -543,7 +543,7 @@
ScopedFastNativeObjectAccess soa(env);
StackHandleScope<1> hs(soa.Self());
Handle<mirror::Class> klass(hs.NewHandle(DecodeClass(soa, javaThis)));
- if (klass->IsAnyProxyClass() || klass->GetDexCache() == nullptr) {
+ if (klass->IsProxyClass() || klass->GetDexCache() == nullptr) {
return nullptr;
}
return soa.AddLocalReference<jclass>(klass->GetDexFile().GetEnclosingClass(klass));
@@ -553,7 +553,7 @@
ScopedFastNativeObjectAccess soa(env);
StackHandleScope<1> hs(soa.Self());
Handle<mirror::Class> klass(hs.NewHandle(DecodeClass(soa, javaThis)));
- if (klass->IsAnyProxyClass() || klass->GetDexCache() == nullptr) {
+ if (klass->IsProxyClass() || klass->GetDexCache() == nullptr) {
return nullptr;
}
mirror::Object* method = klass->GetDexFile().GetEnclosingMethod(klass);
@@ -570,7 +570,7 @@
ScopedFastNativeObjectAccess soa(env);
StackHandleScope<1> hs(soa.Self());
Handle<mirror::Class> klass(hs.NewHandle(DecodeClass(soa, javaThis)));
- if (klass->IsAnyProxyClass() || klass->GetDexCache() == nullptr) {
+ if (klass->IsProxyClass() || klass->GetDexCache() == nullptr) {
return nullptr;
}
mirror::Object* method = klass->GetDexFile().GetEnclosingMethod(klass);
@@ -587,7 +587,7 @@
ScopedFastNativeObjectAccess soa(env);
StackHandleScope<1> hs(soa.Self());
Handle<mirror::Class> klass(hs.NewHandle(DecodeClass(soa, javaThis)));
- if (klass->IsAnyProxyClass() || klass->GetDexCache() == nullptr) {
+ if (klass->IsProxyClass() || klass->GetDexCache() == nullptr) {
return defaultValue;
}
uint32_t flags;
@@ -601,7 +601,7 @@
ScopedFastNativeObjectAccess soa(env);
StackHandleScope<1> hs(soa.Self());
Handle<mirror::Class> klass(hs.NewHandle(DecodeClass(soa, javaThis)));
- if (klass->IsAnyProxyClass() || klass->GetDexCache() == nullptr) {
+ if (klass->IsProxyClass() || klass->GetDexCache() == nullptr) {
return nullptr;
}
mirror::String* class_name = nullptr;
@@ -615,7 +615,7 @@
ScopedFastNativeObjectAccess soa(env);
StackHandleScope<1> hs(soa.Self());
Handle<mirror::Class> klass(hs.NewHandle(DecodeClass(soa, javaThis)));
- if (klass->IsAnyProxyClass() || klass->GetDexCache() == nullptr) {
+ if (klass->IsProxyClass() || klass->GetDexCache() == nullptr) {
return false;
}
mirror::String* class_name = nullptr;
@@ -630,7 +630,7 @@
ScopedFastNativeObjectAccess soa(env);
StackHandleScope<2> hs(soa.Self());
Handle<mirror::Class> klass(hs.NewHandle(DecodeClass(soa, javaThis)));
- if (klass->IsAnyProxyClass() || klass->GetDexCache() == nullptr) {
+ if (klass->IsProxyClass() || klass->GetDexCache() == nullptr) {
return false;
}
Handle<mirror::Class> annotation_class(hs.NewHandle(soa.Decode<mirror::Class*>(annotationType)));
@@ -641,7 +641,7 @@
ScopedFastNativeObjectAccess soa(env);
StackHandleScope<1> hs(soa.Self());
Handle<mirror::Class> klass(hs.NewHandle(DecodeClass(soa, javaThis)));
- if (klass->IsAnyProxyClass() || klass->GetDexCache() == nullptr) {
+ if (klass->IsProxyClass() || klass->GetDexCache() == nullptr) {
return nullptr;
}
// Return null for anonymous classes.
diff --git a/runtime/native/java_lang_reflect_Field.cc b/runtime/native/java_lang_reflect_Field.cc
index 9166ecc..aac800a 100644
--- a/runtime/native/java_lang_reflect_Field.cc
+++ b/runtime/native/java_lang_reflect_Field.cc
@@ -419,7 +419,7 @@
ScopedFastNativeObjectAccess soa(env);
StackHandleScope<1> hs(soa.Self());
ArtField* field = soa.Decode<mirror::Field*>(javaField)->GetArtField();
- if (field->GetDeclaringClass()->IsAnyProxyClass()) {
+ if (field->GetDeclaringClass()->IsProxyClass()) {
return nullptr;
}
Handle<mirror::Class> klass(hs.NewHandle(soa.Decode<mirror::Class*>(annotationType)));
@@ -429,7 +429,7 @@
static jobjectArray Field_getDeclaredAnnotations(JNIEnv* env, jobject javaField) {
ScopedFastNativeObjectAccess soa(env);
ArtField* field = soa.Decode<mirror::Field*>(javaField)->GetArtField();
- if (field->GetDeclaringClass()->IsAnyProxyClass()) {
+ if (field->GetDeclaringClass()->IsProxyClass()) {
// Return an empty array instead of a null pointer.
mirror::Class* annotation_array_class =
soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_annotation_Annotation__array);
@@ -443,7 +443,7 @@
static jobjectArray Field_getSignatureAnnotation(JNIEnv* env, jobject javaField) {
ScopedFastNativeObjectAccess soa(env);
ArtField* field = soa.Decode<mirror::Field*>(javaField)->GetArtField();
- if (field->GetDeclaringClass()->IsAnyProxyClass()) {
+ if (field->GetDeclaringClass()->IsProxyClass()) {
return nullptr;
}
return soa.AddLocalReference<jobjectArray>(
@@ -455,7 +455,7 @@
ScopedFastNativeObjectAccess soa(env);
StackHandleScope<1> hs(soa.Self());
ArtField* field = soa.Decode<mirror::Field*>(javaField)->GetArtField();
- if (field->GetDeclaringClass()->IsAnyProxyClass()) {
+ if (field->GetDeclaringClass()->IsProxyClass()) {
return false;
}
Handle<mirror::Class> klass(hs.NewHandle(soa.Decode<mirror::Class*>(annotationType)));
diff --git a/runtime/native/java_lang_reflect_Method.cc b/runtime/native/java_lang_reflect_Method.cc
index 7894c9b..caacba6 100644
--- a/runtime/native/java_lang_reflect_Method.cc
+++ b/runtime/native/java_lang_reflect_Method.cc
@@ -32,7 +32,7 @@
static jobject Method_getAnnotationNative(JNIEnv* env, jobject javaMethod, jclass annotationType) {
ScopedFastNativeObjectAccess soa(env);
ArtMethod* method = ArtMethod::FromReflectedMethod(soa, javaMethod);
- if (method->GetDeclaringClass()->IsAnyProxyClass()) {
+ if (method->GetDeclaringClass()->IsProxyClass()) {
return nullptr;
}
StackHandleScope<1> hs(soa.Self());
@@ -44,7 +44,7 @@
static jobjectArray Method_getDeclaredAnnotations(JNIEnv* env, jobject javaMethod) {
ScopedFastNativeObjectAccess soa(env);
ArtMethod* method = ArtMethod::FromReflectedMethod(soa, javaMethod);
- if (method->GetDeclaringClass()->IsAnyProxyClass()) {
+ if (method->GetDeclaringClass()->IsProxyClass()) {
// Return an empty array instead of a null pointer.
mirror::Class* annotation_array_class =
soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_annotation_Annotation__array);
@@ -67,7 +67,7 @@
static jobjectArray Method_getExceptionTypes(JNIEnv* env, jobject javaMethod) {
ScopedFastNativeObjectAccess soa(env);
ArtMethod* method = ArtMethod::FromReflectedMethod(soa, javaMethod);
- if (method->GetDeclaringClass()->IsAnyProxyClass()) {
+ if (method->GetDeclaringClass()->IsProxyClass()) {
mirror::Class* klass = method->GetDeclaringClass();
int throws_index = -1;
size_t i = 0;
@@ -79,8 +79,7 @@
++i;
}
CHECK_NE(throws_index, -1);
- mirror::ObjectArray<mirror::Class>* declared_exceptions =
- klass->GetThrowsForAnyProxy()->Get(throws_index);
+ mirror::ObjectArray<mirror::Class>* declared_exceptions = klass->GetThrows()->Get(throws_index);
return soa.AddLocalReference<jobjectArray>(declared_exceptions->Clone(soa.Self()));
} else {
mirror::ObjectArray<mirror::Class>* result_array =
@@ -105,7 +104,7 @@
static jobjectArray Method_getParameterAnnotationsNative(JNIEnv* env, jobject javaMethod) {
ScopedFastNativeObjectAccess soa(env);
ArtMethod* method = ArtMethod::FromReflectedMethod(soa, javaMethod);
- if (method->GetDeclaringClass()->IsAnyProxyClass()) {
+ if (method->GetDeclaringClass()->IsProxyClass()) {
return nullptr;
}
return soa.AddLocalReference<jobjectArray>(method->GetDexFile()->GetParameterAnnotations(method));
@@ -121,7 +120,7 @@
jclass annotationType) {
ScopedFastNativeObjectAccess soa(env);
ArtMethod* method = ArtMethod::FromReflectedMethod(soa, javaMethod);
- if (method->GetDeclaringClass()->IsAnyProxyClass()) {
+ if (method->GetDeclaringClass()->IsProxyClass()) {
return false;
}
StackHandleScope<1> hs(soa.Self());
diff --git a/runtime/native/java_lang_reflect_Proxy.cc b/runtime/native/java_lang_reflect_Proxy.cc
index 647cec0..4a6ab40 100644
--- a/runtime/native/java_lang_reflect_Proxy.cc
+++ b/runtime/native/java_lang_reflect_Proxy.cc
@@ -27,31 +27,15 @@
namespace art {
static jclass Proxy_generateProxy(JNIEnv* env, jclass, jstring name, jobjectArray interfaces,
- jobject loader, jobjectArray methods, jobjectArray throws,
- jboolean is_lambda_proxy) {
+ jobject loader, jobjectArray methods, jobjectArray throws) {
ScopedFastNativeObjectAccess soa(env);
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
-
- mirror::Class* proxy_class = nullptr;
-
- if (UNLIKELY(is_lambda_proxy)) {
- bool already_exists; // XX: Perhaps add lambdaProxyCache to java.lang.ClassLoader ?
- proxy_class = class_linker->CreateLambdaProxyClass(soa,
- name,
- interfaces,
- loader,
- methods,
- throws,
- /*out*/&already_exists);
- } else {
- proxy_class = class_linker->CreateProxyClass(soa, name, interfaces, loader, methods, throws);
- }
-
- return soa.AddLocalReference<jclass>(proxy_class);
+ return soa.AddLocalReference<jclass>(class_linker->CreateProxyClass(
+ soa, name, interfaces, loader, methods, throws));
}
static JNINativeMethod gMethods[] = {
- NATIVE_METHOD(Proxy, generateProxy, "!(Ljava/lang/String;[Ljava/lang/Class;Ljava/lang/ClassLoader;[Ljava/lang/reflect/Method;[[Ljava/lang/Class;Z)Ljava/lang/Class;"),
+ NATIVE_METHOD(Proxy, generateProxy, "!(Ljava/lang/String;[Ljava/lang/Class;Ljava/lang/ClassLoader;[Ljava/lang/reflect/Method;[[Ljava/lang/Class;)Ljava/lang/Class;"),
};
void register_java_lang_reflect_Proxy(JNIEnv* env) {
diff --git a/runtime/proxy_test.cc b/runtime/proxy_test.cc
index 57aafcc..57472ad 100644
--- a/runtime/proxy_test.cc
+++ b/runtime/proxy_test.cc
@@ -121,7 +121,7 @@
GenerateProxyClass(soa, jclass_loader, "$Proxy1234", interfaces)));
interfaces.clear(); // Don't least possibly stale objects in the array as good practice.
ASSERT_TRUE(proxy_class.Get() != nullptr);
- ASSERT_TRUE(proxy_class->IsReflectProxyClass());
+ ASSERT_TRUE(proxy_class->IsProxyClass());
ASSERT_TRUE(proxy_class->IsInitialized());
EXPECT_EQ(2U, proxy_class->NumDirectInterfaces()); // Interfaces$I and Interfaces$J.
@@ -157,7 +157,7 @@
}
ASSERT_TRUE(proxyClass.Get() != nullptr);
- ASSERT_TRUE(proxyClass->IsReflectProxyClass());
+ ASSERT_TRUE(proxyClass->IsProxyClass());
ASSERT_TRUE(proxyClass->IsInitialized());
EXPECT_TRUE(proxyClass->GetIFieldsPtr() == nullptr);
@@ -208,10 +208,10 @@
}
ASSERT_TRUE(proxyClass0.Get() != nullptr);
- ASSERT_TRUE(proxyClass0->IsReflectProxyClass());
+ ASSERT_TRUE(proxyClass0->IsProxyClass());
ASSERT_TRUE(proxyClass0->IsInitialized());
ASSERT_TRUE(proxyClass1.Get() != nullptr);
- ASSERT_TRUE(proxyClass1->IsReflectProxyClass());
+ ASSERT_TRUE(proxyClass1->IsProxyClass());
ASSERT_TRUE(proxyClass1->IsInitialized());
LengthPrefixedArray<ArtField>* static_fields0 = proxyClass0->GetSFieldsPtr();
diff --git a/runtime/stack.cc b/runtime/stack.cc
index 2ff9fd2..9098d38 100644
--- a/runtime/stack.cc
+++ b/runtime/stack.cc
@@ -172,23 +172,12 @@
} else {
return cur_shadow_frame_->GetVRegReference(0);
}
- } else if (m->IsReflectProxyMethod()) {
+ } else if (m->IsProxyMethod()) {
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) {
@@ -825,27 +814,7 @@
// 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";
-
- 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);
- }
+ return runtime->GetCalleeSaveMethodFrameInfo(Runtime::kRefsAndArgs);
}
// The only remaining case is if the method is native and uses the generic JNI stub.