Support directly invoking interface default methods
With the Java 8 Language one is allowed to directly call default
interface methods of interfaces one (directly) implements through the
use of the super keyword. We support this behavior through the
invoke-super opcode with the target being an interface.
We add 3 tests for this behavior.
Currently only supports slow-path interpreter.
Invoke-super is currently extremely slow.
Bug: 24618811
Change-Id: I7e06e17326f7dbae0116bd7dfefca151f0092bd2
diff --git a/compiler/dex/quick/quick_compiler.cc b/compiler/dex/quick/quick_compiler.cc
index 3260a7a..ebc9a2c 100644
--- a/compiler/dex/quick/quick_compiler.cc
+++ b/compiler/dex/quick/quick_compiler.cc
@@ -520,7 +520,12 @@
// In the rare cases we compile experimental opcodes, the runtime has an option to enable it,
// which will force scanning for any unsupported opcodes.
static bool SkipScanningUnsupportedOpcodes(InstructionSet instruction_set) {
- if (UNLIKELY(kUnsupportedOpcodesSize[instruction_set] == 0U)) {
+ Runtime* runtime = Runtime::Current();
+ if (UNLIKELY(runtime->AreExperimentalFlagsEnabled(ExperimentalFlags::kDefaultMethods))) {
+ // Always need to scan opcodes if we have default methods since invoke-super for interface
+ // methods is never going to be supported in the quick compiler.
+ return false;
+ } else if (UNLIKELY(kUnsupportedOpcodesSize[instruction_set] == 0U)) {
// All opcodes are supported no matter what. Usually not the case
// since experimental opcodes are not implemented in the quick compiler.
return true;
@@ -538,8 +543,28 @@
}
}
+bool QuickCompiler::CanCompileInstruction(const MIR* mir,
+ const DexFile& dex_file) const {
+ switch (mir->dalvikInsn.opcode) {
+ // Quick compiler won't support new instruction semantics to invoke-super into an interface
+ // method
+ case Instruction::INVOKE_SUPER: // Fall-through
+ case Instruction::INVOKE_SUPER_RANGE: {
+ DCHECK(mir->dalvikInsn.IsInvoke());
+ uint32_t invoke_method_idx = mir->dalvikInsn.vB;
+ const DexFile::MethodId& method_id = dex_file.GetMethodId(invoke_method_idx);
+ const DexFile::ClassDef* class_def = dex_file.FindClassDef(method_id.class_idx_);
+ // False if we are an interface i.e. !(java_access_flags & kAccInterface)
+ return class_def != nullptr && ((class_def->GetJavaAccessFlags() & kAccInterface) == 0);
+ }
+ default:
+ return true;
+ }
+}
+
// Skip the method that we do not support currently.
-bool QuickCompiler::CanCompileMethod(uint32_t method_idx, const DexFile& dex_file,
+bool QuickCompiler::CanCompileMethod(uint32_t method_idx,
+ const DexFile& dex_file,
CompilationUnit* cu) const {
// This is a limitation in mir_graph. See MirGraph::SetNumSSARegs.
if (cu->mir_graph->GetNumOfCodeAndTempVRs() > kMaxAllowedDalvikRegisters) {
@@ -580,6 +605,9 @@
<< MIRGraph::extended_mir_op_names_[opcode - kMirOpFirst];
}
return false;
+ } else if (!CanCompileInstruction(mir, dex_file)) {
+ VLOG(compiler) << "Cannot compile dalvik opcode : " << mir->dalvikInsn.opcode;
+ return false;
}
// Check if it invokes a prototype that we cannot support.
if (std::find(kInvokeOpcodes, kInvokeOpcodes + arraysize(kInvokeOpcodes), opcode)