Correct exception behavior for default methods
Default methods are defined to throw an IncompatibleClassChangeError
(ICCE) when they are called and there is no "best" implementation.
Previously we would simply throw an ICCE during class loading as soon
as we noticed that this would happen if called. This makes us wait
until we actually attempt to execute the method. Furthermore, this
allows us to use other, non-conflicting, methods on the object as
normal.
Furthermore, this makes us correctly throw AbstractMethodErrors in
cases where all default implementations of a method are overridden by
abstract declarations.
Adds 3 tests for this new behavior.
Bug: 24618811
Change-Id: Id891958a81f9b3862b2ce5919636aabef7d3422e
diff --git a/compiler/image_writer.cc b/compiler/image_writer.cc
index 7c1281f..dd2ea9e 100644
--- a/compiler/image_writer.cc
+++ b/compiler/image_writer.cc
@@ -1621,7 +1621,7 @@
DCHECK(!method->IsResolutionMethod()) << PrettyMethod(method);
DCHECK(!method->IsImtConflictMethod()) << PrettyMethod(method);
DCHECK(!method->IsImtUnimplementedMethod()) << PrettyMethod(method);
- DCHECK(!method->IsAbstract()) << PrettyMethod(method);
+ DCHECK(method->IsInvokable()) << PrettyMethod(method);
DCHECK(!IsInBootImage(method)) << PrettyMethod(method);
// Use original code if it exists. Otherwise, set the code pointer to the resolution
@@ -1668,7 +1668,7 @@
// We assume all methods have code. If they don't currently then we set them to the use the
// resolution trampoline. Abstract methods never have code and so we need to make sure their
// use results in an AbstractMethodError. We use the interpreter to achieve this.
- if (UNLIKELY(method->IsAbstract())) {
+ if (UNLIKELY(!method->IsInvokable())) {
return GetOatAddress(kOatAddressQuickToInterpreterBridge);
} else {
bool quick_is_interpreted;
@@ -1714,7 +1714,7 @@
// We assume all methods have code. If they don't currently then we set them to the use the
// resolution trampoline. Abstract methods never have code and so we need to make sure their
// use results in an AbstractMethodError. We use the interpreter to achieve this.
- if (UNLIKELY(orig->IsAbstract())) {
+ if (UNLIKELY(!orig->IsInvokable())) {
copy->SetEntryPointFromQuickCompiledCodePtrSize(
GetOatAddress(kOatAddressQuickToInterpreterBridge), target_ptr_size_);
} else {