Enable interface default methods by default.
This also enables interface static methods.
This removes the -Xexperimental:default-methods flag and all places
where we explicitly check for its presence.
Bug: 24618811
Change-Id: Icd91e377bd6e1a45a1645f810d15de1b0312e31d
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index ed833c4..5e4b3a6 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -5523,15 +5523,6 @@
Runtime* const runtime = Runtime::Current();
const bool is_interface = klass->IsInterface();
- // TODO It might in the future prove useful to make interfaces have full iftables, allowing a
- // faster invoke-super implementation in the interpreter/across dex-files.
- // We will just skip doing any of this on non-debug builds for speed.
- if (is_interface &&
- !kIsDebugBuild &&
- !runtime->AreExperimentalFlagsEnabled(ExperimentalFlags::kDefaultMethods)) {
- return true;
- }
-
const bool has_superclass = klass->HasSuperClass();
const bool fill_tables = !is_interface;
const size_t super_ifcount = has_superclass ? klass->GetSuperClass()->GetIfTableCount() : 0U;
diff --git a/runtime/dex_file_verifier.cc b/runtime/dex_file_verifier.cc
index 727f4fc..7a852e2 100644
--- a/runtime/dex_file_verifier.cc
+++ b/runtime/dex_file_verifier.cc
@@ -2538,20 +2538,6 @@
return false;
}
- // Only the static initializer may have code in an interface.
- // TODO We should have some way determine whether to allow this experimental flag without the
- // runtime being started.
- // We assume experimental flags are enabled when running without a runtime to enable tools like
- // dexdump to handle dex files with these features.
- if (((class_access_flags & kAccInterface) != 0)
- && !is_clinit_by_name
- && Runtime::Current() != nullptr
- && !Runtime::Current()->AreExperimentalFlagsEnabled(ExperimentalFlags::kDefaultMethods)) {
- *error_msg = StringPrintf("Non-clinit interface method %" PRIu32 " should not have code",
- method_index);
- return false;
- }
-
// Instance constructors must not be synchronized and a few other flags.
if (is_init_by_name) {
static constexpr uint32_t kInitAllowed =
diff --git a/runtime/experimental_flags.h b/runtime/experimental_flags.h
index 2e674e9..198f3fa 100644
--- a/runtime/experimental_flags.h
+++ b/runtime/experimental_flags.h
@@ -27,7 +27,6 @@
enum {
kNone = 0x0000,
kLambdas = 0x0001,
- kDefaultMethods = 0x0002,
};
constexpr ExperimentalFlags() : value_(0x0000) {}
@@ -69,10 +68,6 @@
stream << (started ? "|" : "") << "kLambdas";
started = true;
}
- if (e & ExperimentalFlags::kDefaultMethods) {
- stream << (started ? "|" : "") << "kDefaultMethods";
- started = true;
- }
if (!started) {
stream << "kNone";
}
diff --git a/runtime/parsed_options.cc b/runtime/parsed_options.cc
index 341be9a..aa64ee3 100644
--- a/runtime/parsed_options.cc
+++ b/runtime/parsed_options.cc
@@ -565,13 +565,6 @@
args.Set(M::HeapGrowthLimit, args.GetOrDefault(M::MemoryMaximumSize));
}
- if (args.GetOrDefault(M::Experimental) & ExperimentalFlags::kDefaultMethods) {
- LOG(WARNING) << "Default method support has been enabled. The verifier will be less strict "
- << "in some cases. All existing invoke opcodes have an unstable updated "
- << "specification and are nearly guaranteed to change over time. Do not attempt "
- << "to write shipping code against the invoke opcodes with this flag.";
- }
-
if (args.GetOrDefault(M::Experimental) & ExperimentalFlags::kLambdas) {
LOG(WARNING) << "Experimental lambdas have been enabled. All lambda opcodes have "
<< "an unstable specification and are nearly guaranteed to change over time. "
@@ -698,8 +691,8 @@
UsageMessage(stream, " -X[no]image-dex2oat (Whether to create and use a boot image)\n");
UsageMessage(stream, " -Xno-dex-file-fallback "
"(Don't fall back to dex files without oat files)\n");
- UsageMessage(stream, " -Xexperimental:{lambdas,default-methods} "
- "(Enable new experimental dalvik opcodes and semantics, off by default)\n");
+ UsageMessage(stream, " -Xexperimental:lambdas "
+ "(Enable new and experimental dalvik opcodes and semantics)\n");
UsageMessage(stream, "\n");
UsageMessage(stream, "The following previously supported Dalvik options are ignored:\n");
diff --git a/runtime/runtime_options.def b/runtime/runtime_options.def
index c5b009d..308f3ba 100644
--- a/runtime/runtime_options.def
+++ b/runtime/runtime_options.def
@@ -113,7 +113,7 @@
RUNTIME_OPTIONS_KEY (Unit, NoDexFileFallback)
RUNTIME_OPTIONS_KEY (std::string, CpuAbiList)
RUNTIME_OPTIONS_KEY (std::string, Fingerprint)
-RUNTIME_OPTIONS_KEY (ExperimentalFlags, Experimental, ExperimentalFlags::kNone) // -Xexperimental:{, lambdas, default-methods}
+RUNTIME_OPTIONS_KEY (ExperimentalFlags, Experimental, ExperimentalFlags::kNone) // -Xexperimental:{none, lambdas}
// Not parse-able from command line, but can be provided explicitly.
// (Do not add anything here that is defined in ParsedOptions::MakeParser)
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index 7e0f337..2890a98 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -608,7 +608,6 @@
bool MethodVerifier::Verify() {
// Some older code doesn't correctly mark constructors as such. Test for this case by looking at
// the name.
- Runtime* runtime = Runtime::Current();
const DexFile::MethodId& method_id = dex_file_->GetMethodId(dex_method_idx_);
const char* method_name = dex_file_->StringDataByIdx(method_id.name_idx_);
bool instance_constructor_by_name = strcmp("<init>", method_name) == 0;
@@ -678,12 +677,9 @@
}
if ((class_def_->GetJavaAccessFlags() & kAccInterface) != 0) {
// Interface methods must be public and abstract (if default methods are disabled).
- bool default_methods_supported =
- runtime->AreExperimentalFlagsEnabled(ExperimentalFlags::kDefaultMethods);
- uint32_t kRequired = kAccPublic | (default_methods_supported ? 0 : kAccAbstract);
+ uint32_t kRequired = kAccPublic;
if ((method_access_flags_ & kRequired) != kRequired) {
- Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "interface methods must be public"
- << (default_methods_supported ? "" : " and abstract");
+ Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "interface methods must be public";
return false;
}
// In addition to the above, interface methods must not be protected.
@@ -715,19 +711,14 @@
// default methods enabled we also allow other public, static, non-final methods to have code.
// Otherwise that is the only type of method allowed.
if (!(IsConstructor() && IsStatic())) {
- if (runtime->AreExperimentalFlagsEnabled(ExperimentalFlags::kDefaultMethods)) {
- if (IsInstanceConstructor()) {
- Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "interfaces may not have non-static constructor";
- return false;
- } else if (method_access_flags_ & kAccFinal) {
- Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "interfaces may not have final methods";
- return false;
- } else if (!(method_access_flags_ & kAccPublic)) {
- Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "interfaces may not have non-public members";
- return false;
- }
- } else {
- Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "interface methods must be abstract";
+ if (IsInstanceConstructor()) {
+ Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "interfaces may not have non-static constructor";
+ return false;
+ } else if (method_access_flags_ & kAccFinal) {
+ Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "interfaces may not have final methods";
+ return false;
+ } else if (!(method_access_flags_ & kAccPublic)) {
+ Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "interfaces may not have non-public members";
return false;
}
}
@@ -3713,12 +3704,10 @@
// Note: this check must be after the initializer check, as those are required to fail a class,
// while this check implies an IncompatibleClassChangeError.
if (klass->IsInterface()) {
- Runtime* runtime = Runtime::Current();
- const bool default_methods_supported =
- runtime == nullptr ||
- runtime->AreExperimentalFlagsEnabled(ExperimentalFlags::kDefaultMethods);
+ // methods called on interfaces should be invoke-interface, invoke-super, or invoke-static.
if (method_type != METHOD_INTERFACE &&
- (!default_methods_supported || method_type != METHOD_STATIC)) {
+ method_type != METHOD_STATIC &&
+ method_type != METHOD_SUPER) {
Fail(VERIFY_ERROR_CLASS_CHANGE)
<< "non-interface method " << PrettyMethod(dex_method_idx, *dex_file_)
<< " is in an interface class " << PrettyClass(klass);