Merge changes If0d5eeeb,Id927f2b5
* changes:
ART: Fix and extend test 904
ART: Better handle multiple event enables
diff --git a/cmdline/cmdline.h b/cmdline/cmdline.h
index 4dcaf80..dec9c83 100644
--- a/cmdline/cmdline.h
+++ b/cmdline/cmdline.h
@@ -293,7 +293,7 @@
template <typename Args = CmdlineArgs>
struct CmdlineMain {
int Main(int argc, char** argv) {
- InitLogging(argv);
+ InitLogging(argv, Runtime::Aborter);
std::unique_ptr<Args> args = std::unique_ptr<Args>(CreateArguments());
args_ = args.get();
diff --git a/cmdline/cmdline_parser_test.cc b/cmdline/cmdline_parser_test.cc
index 5809dcd..cad5104 100644
--- a/cmdline/cmdline_parser_test.cc
+++ b/cmdline/cmdline_parser_test.cc
@@ -122,7 +122,7 @@
using RuntimeParser = ParsedOptions::RuntimeParser;
static void SetUpTestCase() {
- art::InitLogging(nullptr); // argv = null
+ art::InitLogging(nullptr, art::Runtime::Aborter); // argv = null
}
virtual void SetUp() {
diff --git a/compiler/image_writer.cc b/compiler/image_writer.cc
index fbdb115..8f15ea4 100644
--- a/compiler/image_writer.cc
+++ b/compiler/image_writer.cc
@@ -461,6 +461,12 @@
dex_cache);
DCHECK_EQ(dex_file->NumStringIds() != 0u, dex_cache->GetStrings() != nullptr);
AddDexCacheArrayRelocation(dex_cache->GetStrings(), start + layout.StringsOffset(), dex_cache);
+
+ if (dex_cache->GetResolvedMethodTypes() != nullptr) {
+ AddDexCacheArrayRelocation(dex_cache->GetResolvedMethodTypes(),
+ start + layout.MethodTypesOffset(),
+ dex_cache);
+ }
}
}
@@ -2170,6 +2176,14 @@
mirror::DexCache::SetElementPtrSize(copy_fields, i, copy, target_ptr_size_);
}
}
+ mirror::MethodTypeDexCacheType* orig_method_types = orig_dex_cache->GetResolvedMethodTypes();
+ if (orig_method_types != nullptr) {
+ copy_dex_cache->SetFieldPtrWithSize<false>(mirror::DexCache::ResolvedMethodTypesOffset(),
+ NativeLocationInImage(orig_method_types),
+ PointerSize::k64);
+ orig_dex_cache->FixupResolvedMethodTypes(NativeCopyLocation(orig_method_types, orig_dex_cache),
+ ImageAddressVisitor(this));
+ }
// Remove the DexFile pointers. They will be fixed up when the runtime loads the oat file. Leaving
// compiler pointers in here will make the output non-deterministic.
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index 57d4386..0ce1362 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -1090,7 +1090,7 @@
original_argc = argc;
original_argv = argv;
- InitLogging(argv);
+ InitLogging(argv, Runtime::Aborter);
// Skip over argv[0].
argv++;
diff --git a/dexdump/dexdump_main.cc b/dexdump/dexdump_main.cc
index 5c032a0..74cae3c 100644
--- a/dexdump/dexdump_main.cc
+++ b/dexdump/dexdump_main.cc
@@ -29,6 +29,7 @@
#include <unistd.h>
#include "base/logging.h"
+#include "runtime.h"
#include "mem_map.h"
namespace art {
@@ -59,7 +60,7 @@
*/
int dexdumpDriver(int argc, char** argv) {
// Art specific set up.
- InitLogging(argv);
+ InitLogging(argv, Runtime::Aborter);
MemMap::Init();
// Reset options.
diff --git a/dexlayout/dexlayout_main.cc b/dexlayout/dexlayout_main.cc
index 728e389..2203fba 100644
--- a/dexlayout/dexlayout_main.cc
+++ b/dexlayout/dexlayout_main.cc
@@ -31,6 +31,7 @@
#include "base/logging.h"
#include "jit/offline_profiling_info.h"
+#include "runtime.h"
#include "mem_map.h"
namespace art {
@@ -65,7 +66,7 @@
*/
int DexlayoutDriver(int argc, char** argv) {
// Art specific set up.
- InitLogging(argv);
+ InitLogging(argv, Runtime::Aborter);
MemMap::Init();
// Reset options.
diff --git a/dexlist/dexlist.cc b/dexlist/dexlist.cc
index a1bde0e..68473c4 100644
--- a/dexlist/dexlist.cc
+++ b/dexlist/dexlist.cc
@@ -213,7 +213,7 @@
*/
int dexlistDriver(int argc, char** argv) {
// Art specific set up.
- InitLogging(argv);
+ InitLogging(argv, Runtime::Aborter);
MemMap::Init();
// Reset options.
diff --git a/patchoat/patchoat.cc b/patchoat/patchoat.cc
index d6b52db..986f265 100644
--- a/patchoat/patchoat.cc
+++ b/patchoat/patchoat.cc
@@ -677,6 +677,16 @@
mirror::DexCache::SetElementPtrSize(copy_fields, j, copy, pointer_size);
}
}
+ mirror::MethodTypeDexCacheType* orig_method_types = orig_dex_cache->GetResolvedMethodTypes();
+ mirror::MethodTypeDexCacheType* relocated_method_types =
+ RelocatedAddressOfPointer(orig_method_types);
+ copy_dex_cache->SetField64<false>(
+ mirror::DexCache::ResolvedMethodTypesOffset(),
+ static_cast<int64_t>(reinterpret_cast<uintptr_t>(relocated_method_types)));
+ if (orig_method_types != nullptr) {
+ orig_dex_cache->FixupResolvedMethodTypes(RelocatedCopyOf(orig_method_types),
+ RelocatedPointerVisitor(this));
+ }
}
}
@@ -1360,15 +1370,13 @@
}
static int patchoat(int argc, char **argv) {
- InitLogging(argv);
+ InitLogging(argv, Runtime::Aborter);
MemMap::Init();
const bool debug = kIsDebugBuild;
orig_argc = argc;
orig_argv = argv;
TimingLogger timings("patcher", false, false);
- InitLogging(argv);
-
// Skip over the command name.
argv++;
argc--;
diff --git a/profman/profman.cc b/profman/profman.cc
index 7722e80..b17816b 100644
--- a/profman/profman.cc
+++ b/profman/profman.cc
@@ -33,6 +33,7 @@
#include "base/unix_file/fd_file.h"
#include "dex_file.h"
#include "jit/offline_profiling_info.h"
+#include "runtime.h"
#include "utils.h"
#include "zip_archive.h"
#include "profile_assistant.h"
@@ -143,7 +144,7 @@
original_argc = argc;
original_argv = argv;
- InitLogging(argv);
+ InitLogging(argv, Runtime::Aborter);
// Skip over the command name.
argv++;
diff --git a/runtime/art_method-inl.h b/runtime/art_method-inl.h
index 73c6cf1..1aa6a00 100644
--- a/runtime/art_method-inl.h
+++ b/runtime/art_method-inl.h
@@ -227,9 +227,10 @@
case kDirect:
return !IsDirect() || IsStatic();
case kVirtual: {
- // We have an error if we are direct or a non-default, non-miranda interface method.
+ // We have an error if we are direct or a non-copied (i.e. not part of a real class) interface
+ // method.
mirror::Class* methods_class = GetDeclaringClass();
- return IsDirect() || (methods_class->IsInterface() && !IsDefault() && !IsMiranda());
+ return IsDirect() || (methods_class->IsInterface() && !IsCopied());
}
case kSuper:
// Constructors and static methods are called with invoke-direct.
diff --git a/runtime/base/logging.cc b/runtime/base/logging.cc
index 08c036e..6b21a56 100644
--- a/runtime/base/logging.cc
+++ b/runtime/base/logging.cc
@@ -21,14 +21,12 @@
#include <sstream>
#include "base/mutex.h"
-#include "runtime.h"
#include "thread-inl.h"
#include "utils.h"
// Headers for LogMessage::LogLine.
#ifdef ART_TARGET_ANDROID
#include <android/log.h>
-#include <android/set_abort_message.h>
#else
#include <sys/types.h>
#include <unistd.h>
@@ -57,17 +55,7 @@
: "art";
}
-NO_RETURN
-static void RuntimeAborter(const char* abort_message) {
-#ifdef __ANDROID__
- android_set_abort_message(abort_message);
-#else
- UNUSED(abort_message);
-#endif
- Runtime::Abort(abort_message);
-}
-
-void InitLogging(char* argv[]) {
+void InitLogging(char* argv[], AbortFunction& abort_function) {
if (gCmdLine.get() != nullptr) {
return;
}
@@ -97,7 +85,8 @@
#else
#define INIT_LOGGING_DEFAULT_LOGGER android::base::StderrLogger
#endif
- android::base::InitLogging(argv, INIT_LOGGING_DEFAULT_LOGGER, RuntimeAborter);
+ android::base::InitLogging(argv, INIT_LOGGING_DEFAULT_LOGGER,
+ std::move<AbortFunction>(abort_function));
#undef INIT_LOGGING_DEFAULT_LOGGER
}
diff --git a/runtime/base/logging.h b/runtime/base/logging.h
index 5f84204..a173ac2 100644
--- a/runtime/base/logging.h
+++ b/runtime/base/logging.h
@@ -29,6 +29,9 @@
using ::android::base::LogSeverity;
using ::android::base::ScopedLogSeverity;
+// Abort function.
+using AbortFunction = void(const char*);
+
// The members of this struct are the valid arguments to VLOG and VLOG_IS_ON in code,
// and the "-verbose:" command line argument.
struct LogVerbosity {
@@ -71,7 +74,7 @@
// The tag (or '*' for the global level) comes first, followed by a colon
// and a letter indicating the minimum priority level we're expected to log.
// This can be used to reveal or conceal logs with specific tags.
-extern void InitLogging(char* argv[]);
+extern void InitLogging(char* argv[], AbortFunction& default_aborter);
// Returns the command line used to invoke the current tool or null if InitLogging hasn't been
// performed.
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 239cdae..d07aa89 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -1374,6 +1374,7 @@
std::memory_order_relaxed);
}
+ mirror::MethodTypeDexCachePair::Initialize(method_types);
dex_cache->SetResolvedMethodTypes(method_types);
}
}
diff --git a/runtime/common_runtime_test.cc b/runtime/common_runtime_test.cc
index 193f6ee..5409fcb 100644
--- a/runtime/common_runtime_test.cc
+++ b/runtime/common_runtime_test.cc
@@ -57,7 +57,7 @@
// everything else. In case you want to see all messages, comment out the line.
setenv("ANDROID_LOG_TAGS", "*:e", 1);
- art::InitLogging(argv);
+ art::InitLogging(argv, art::Runtime::Aborter);
LOG(INFO) << "Running main() from common_runtime_test.cc...";
testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
diff --git a/runtime/gc/space/image_space.cc b/runtime/gc/space/image_space.cc
index 81850067..e9c8b95 100644
--- a/runtime/gc/space/image_space.cc
+++ b/runtime/gc/space/image_space.cc
@@ -1255,6 +1255,16 @@
}
}
}
+
+ mirror::MethodTypeDexCacheType* method_types = dex_cache->GetResolvedMethodTypes();
+ if (method_types != nullptr) {
+ mirror::MethodTypeDexCacheType* new_method_types =
+ fixup_adapter.ForwardObject(method_types);
+ if (method_types != new_method_types) {
+ dex_cache->SetResolvedMethodTypes(new_method_types);
+ }
+ dex_cache->FixupResolvedMethodTypes<kWithoutReadBarrier>(new_method_types, fixup_adapter);
+ }
}
}
{
diff --git a/runtime/instrumentation.cc b/runtime/instrumentation.cc
index bed489f..36e8608 100644
--- a/runtime/instrumentation.cc
+++ b/runtime/instrumentation.cc
@@ -650,7 +650,11 @@
// Note: ResetQuickAllocEntryPoints only works when the runtime is started. Manually run the
// update for just this thread.
- ResetQuickAllocEntryPointsForThread(self, nullptr);
+ // Note: self may be null. One of those paths is setting instrumentation in the Heap
+ // constructor for gcstress mode.
+ if (self != nullptr) {
+ ResetQuickAllocEntryPointsForThread(self, nullptr);
+ }
alloc_entrypoints_instrumented_ = instrumented;
}
diff --git a/runtime/mirror/dex_cache-inl.h b/runtime/mirror/dex_cache-inl.h
index 13d0108..86b5e7a 100644
--- a/runtime/mirror/dex_cache-inl.h
+++ b/runtime/mirror/dex_cache-inl.h
@@ -208,6 +208,19 @@
}
}
+template <ReadBarrierOption kReadBarrierOption, typename Visitor>
+inline void DexCache::FixupResolvedMethodTypes(mirror::MethodTypeDexCacheType* dest,
+ const Visitor& visitor) {
+ mirror::MethodTypeDexCacheType* src = GetResolvedMethodTypes();
+ for (size_t i = 0, count = NumResolvedMethodTypes(); i < count; ++i) {
+ MethodTypeDexCachePair source = src[i].load(std::memory_order_relaxed);
+ mirror::MethodType* ptr = source.object.Read<kReadBarrierOption>();
+ mirror::MethodType* new_source = visitor(ptr);
+ source.object = GcRoot<MethodType>(new_source);
+ dest[i].store(source, std::memory_order_relaxed);
+ }
+}
+
} // namespace mirror
} // namespace art
diff --git a/runtime/mirror/dex_cache.h b/runtime/mirror/dex_cache.h
index bbe98c2..c3c7ab4 100644
--- a/runtime/mirror/dex_cache.h
+++ b/runtime/mirror/dex_cache.h
@@ -160,6 +160,10 @@
void FixupResolvedTypes(GcRoot<mirror::Class>* dest, const Visitor& visitor)
REQUIRES_SHARED(Locks::mutator_lock_);
+ template <ReadBarrierOption kReadBarrierOption = kWithReadBarrier, typename Visitor>
+ void FixupResolvedMethodTypes(MethodTypeDexCacheType* dest, const Visitor& visitor)
+ REQUIRES_SHARED(Locks::mutator_lock_);
+
String* GetLocation() REQUIRES_SHARED(Locks::mutator_lock_) {
return GetFieldObject<String>(OFFSET_OF_OBJECT_MEMBER(DexCache, location_));
}
@@ -283,7 +287,7 @@
MethodTypeDexCacheType* GetResolvedMethodTypes()
ALWAYS_INLINE REQUIRES_SHARED(Locks::mutator_lock_) {
- return GetFieldPtr<MethodTypeDexCacheType*>(ResolvedMethodTypesOffset());
+ return GetFieldPtr64<MethodTypeDexCacheType*>(ResolvedMethodTypesOffset());
}
void SetResolvedMethodTypes(MethodTypeDexCacheType* resolved_method_types)
diff --git a/runtime/monitor_android.cc b/runtime/monitor_android.cc
index 0d1839b..1dd60f8 100644
--- a/runtime/monitor_android.cc
+++ b/runtime/monitor_android.cc
@@ -21,7 +21,7 @@
#include <sys/stat.h>
#include <sys/types.h>
-#include <android/log.h>
+#include <log/log.h>
#define EVENT_LOG_TAG_dvm_lock_sample 20003
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index baa4046..6e15c38 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -147,6 +147,10 @@
#include "verifier/method_verifier.h"
#include "well_known_classes.h"
+#ifdef ART_TARGET_ANDROID
+#include <android/set_abort_message.h>
+#endif
+
namespace art {
// If a signal isn't handled properly, enable a handler that attempts to dump the Java stack.
@@ -495,7 +499,7 @@
bool Runtime::ParseOptions(const RuntimeOptions& raw_options,
bool ignore_unrecognized,
RuntimeArgumentMap* runtime_options) {
- InitLogging(/* argv */ nullptr); // Calls Locks::Init() as a side effect.
+ InitLogging(/* argv */ nullptr, Aborter); // Calls Locks::Init() as a side effect.
bool parsed = ParsedOptions::Parse(raw_options, ignore_unrecognized, runtime_options);
if (!parsed) {
LOG(ERROR) << "Failed to parse options";
@@ -2095,4 +2099,12 @@
}
}
+NO_RETURN
+void Runtime::Aborter(const char* abort_message) {
+#ifdef __ANDROID__
+ android_set_abort_message(abort_message);
+#endif
+ Runtime::Abort(abort_message);
+}
+
} // namespace art
diff --git a/runtime/runtime.h b/runtime/runtime.h
index 66fd058..e2ba262 100644
--- a/runtime/runtime.h
+++ b/runtime/runtime.h
@@ -662,6 +662,9 @@
void AddSystemWeakHolder(gc::AbstractSystemWeakHolder* holder);
void RemoveSystemWeakHolder(gc::AbstractSystemWeakHolder* holder);
+ NO_RETURN
+ static void Aborter(const char* abort_message);
+
private:
static void InitPlatformSignalHandlers();
diff --git a/runtime/utils/dex_cache_arrays_layout-inl.h b/runtime/utils/dex_cache_arrays_layout-inl.h
index 5ccd446..5ca7684 100644
--- a/runtime/utils/dex_cache_arrays_layout-inl.h
+++ b/runtime/utils/dex_cache_arrays_layout-inl.h
@@ -39,7 +39,7 @@
fields_offset_(
RoundUp(strings_offset_ + StringsSize(header.string_ids_size_), FieldsAlignment())),
method_types_offset_(
- RoundUp(fields_offset_ + FieldsSize(header.field_ids_size_), Alignment())),
+ RoundUp(fields_offset_ + FieldsSize(header.field_ids_size_), MethodTypesAlignment())),
size_(
RoundUp(method_types_offset_ + MethodTypesSize(header.proto_ids_size_), Alignment())) {
}
@@ -51,7 +51,11 @@
inline constexpr size_t DexCacheArraysLayout::Alignment() {
// GcRoot<> alignment is 4, i.e. lower than or equal to the pointer alignment.
static_assert(alignof(GcRoot<mirror::Class>) == 4, "Expecting alignof(GcRoot<>) == 4");
- static_assert(alignof(mirror::StringDexCacheType) == 8, "Expecting alignof(StringDexCacheType) == 8");
+ static_assert(alignof(mirror::StringDexCacheType) == 8,
+ "Expecting alignof(StringDexCacheType) == 8");
+ static_assert(alignof(mirror::MethodTypeDexCacheType) == 8,
+ "Expecting alignof(MethodTypeDexCacheType) == 8");
+ // This is the same as alignof(MethodTypeDexCacheType).
return alignof(mirror::StringDexCacheType);
}
@@ -120,12 +124,6 @@
return static_cast<size_t>(pointer_size_);
}
-inline size_t DexCacheArraysLayout::MethodTypeOffset(uint32_t proto_idx) const {
- return strings_offset_
- + ElementOffset(PointerSize::k64,
- proto_idx % mirror::DexCache::kDexCacheMethodTypeCacheSize);
-}
-
inline size_t DexCacheArraysLayout::MethodTypesSize(size_t num_elements) const {
size_t cache_size = mirror::DexCache::kDexCacheMethodTypeCacheSize;
if (num_elements < cache_size) {
diff --git a/runtime/utils/dex_cache_arrays_layout.h b/runtime/utils/dex_cache_arrays_layout.h
index e222b46..ae3bfab 100644
--- a/runtime/utils/dex_cache_arrays_layout.h
+++ b/runtime/utils/dex_cache_arrays_layout.h
@@ -99,8 +99,6 @@
return method_types_offset_;
}
- size_t MethodTypeOffset(uint32_t method_type_idx) const;
-
size_t MethodTypesSize(size_t num_elements) const;
size_t MethodTypesAlignment() const;
diff --git a/test/978-virtual-interface/build b/test/978-virtual-interface/build
new file mode 100755
index 0000000..14230c2
--- /dev/null
+++ b/test/978-virtual-interface/build
@@ -0,0 +1,20 @@
+#!/bin/bash
+#
+# Copyright 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.
+
+# make us exit on a failure
+set -e
+
+./default-build "$@" --experimental default-methods
diff --git a/test/978-virtual-interface/expected.txt b/test/978-virtual-interface/expected.txt
new file mode 100644
index 0000000..99071b1
--- /dev/null
+++ b/test/978-virtual-interface/expected.txt
@@ -0,0 +1 @@
+Recieved expected ICCE error!
diff --git a/test/978-virtual-interface/info.txt b/test/978-virtual-interface/info.txt
new file mode 100644
index 0000000..0b8a39f
--- /dev/null
+++ b/test/978-virtual-interface/info.txt
@@ -0,0 +1,7 @@
+Smali-based regression test for b/32201623
+
+This test cannot be run with --jvm.
+
+This test checks that we correctly detect when one attempts to invoke an
+interface method via the invoke-virtual opcode and that correct exceptions are
+sent.
diff --git a/test/978-virtual-interface/smali/Iface.smali b/test/978-virtual-interface/smali/Iface.smali
new file mode 100644
index 0000000..9c3ef7a
--- /dev/null
+++ b/test/978-virtual-interface/smali/Iface.smali
@@ -0,0 +1,110 @@
+# /*
+# * 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.
+# */
+#
+# // Methods are sorted in alphabetical order in dex file. We need 10 padding
+# // methods to ensure the 11'th target lines up to the same vtable slot as the
+# // first Subtype virtual method (the other 10 are the java/lang/Object;
+# // methods).
+# interface Iface {
+# public default void fakeMethod_A() {}
+# public default void fakeMethod_B() {}
+# public default void fakeMethod_C() {}
+# public default void fakeMethod_D() {}
+# public default void fakeMethod_E() {}
+# public default void fakeMethod_F() {}
+# public default void fakeMethod_G() {}
+# public default void fakeMethod_H() {}
+# public default void fakeMethod_I() {}
+# public default void fakeMethod_J() {}
+# public default void fakeMethod_K() {}
+# public default void fakeMethod_Target() {}
+# }
+
+.class public abstract interface LIface;
+
+.super Ljava/lang/Object;
+
+# // 1
+.method public fakeMethod_A()V
+ .locals 0
+ return-void
+.end method
+
+# // 2
+.method public fakeMethod_B()V
+ .locals 0
+ return-void
+.end method
+
+# // 3
+.method public fakeMethod_C()V
+ .locals 0
+ return-void
+.end method
+
+# // 4
+.method public fakeMethod_D()V
+ .locals 0
+ return-void
+.end method
+
+# // 5
+.method public fakeMethod_E()V
+ .locals 0
+ return-void
+.end method
+
+# // 5
+.method public fakeMethod_F()V
+ .locals 0
+ return-void
+.end method
+
+# // 6
+.method public fakeMethod_G()V
+ .locals 0
+ return-void
+.end method
+
+# // 7
+.method public fakeMethod_H()V
+ .locals 0
+ return-void
+.end method
+
+# // 8
+.method public fakeMethod_I()V
+ .locals 0
+ return-void
+.end method
+
+# // 9
+.method public fakeMethod_J()V
+ .locals 0
+ return-void
+.end method
+
+# // 10
+.method public fakeMethod_K()V
+ .locals 0
+ return-void
+.end method
+
+# // 11
+.method public fakeMethod_Target()V
+ .locals 0
+ return-void
+.end method
diff --git a/test/978-virtual-interface/smali/Main.smali b/test/978-virtual-interface/smali/Main.smali
new file mode 100644
index 0000000..61b82f3
--- /dev/null
+++ b/test/978-virtual-interface/smali/Main.smali
@@ -0,0 +1,50 @@
+# /*
+# * 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.
+# */
+#
+# public class Main {
+# public static void main(String[] s) {
+# Subtype s = new Subtype();
+# try {
+# s.callPackage();
+# System.out.println("No error thrown!");
+# } catch (IncompatibleClassChangeError e) {
+# System.out.println("Recieved expected ICCE error!");
+# }
+# }
+# }
+
+.class public LMain;
+
+.super Ljava/lang/Object;
+
+.method public static main([Ljava/lang/String;)V
+ .locals 3
+
+ new-instance v0, LSubtype;
+ invoke-direct {v0}, LSubtype;-><init>()V
+ sget-object v2, Ljava/lang/System;->out:Ljava/io/PrintStream;
+ :try_start
+ invoke-virtual {v0}, LSubtype;->callPackage()V
+ const-string v1, "No error thrown!"
+ invoke-virtual {v2, v1}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V
+ return-void
+ :try_end
+ .catch Ljava/lang/IncompatibleClassChangeError; {:try_start .. :try_end} :error_start
+ :error_start
+ const-string v1, "Recieved expected ICCE error!"
+ invoke-virtual {v2, v1}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V
+ return-void
+.end method
diff --git a/test/978-virtual-interface/smali/Subtype.smali b/test/978-virtual-interface/smali/Subtype.smali
new file mode 100644
index 0000000..f876cf9
--- /dev/null
+++ b/test/978-virtual-interface/smali/Subtype.smali
@@ -0,0 +1,40 @@
+# /*
+# * 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.
+# */
+#
+# public class Subtype extends pkg.Target implements Iface{
+# public void callPackage() {
+# // Fake into a virtual call.
+# // ((Iface)this).fakeMethod_Target();
+# }
+# }
+
+.class public LSubtype;
+
+.super Lpkg/Target;
+
+.implements LIface;
+
+.method public constructor <init>()V
+ .locals 0
+ invoke-direct {p0}, Lpkg/Target;-><init>()V
+ return-void
+.end method
+
+.method public callPackage()V
+ .locals 0
+ invoke-virtual {p0}, LIface;->fakeMethod_Target()V
+ return-void
+.end method
diff --git a/test/978-virtual-interface/smali/Target.smali b/test/978-virtual-interface/smali/Target.smali
new file mode 100644
index 0000000..70108fb
--- /dev/null
+++ b/test/978-virtual-interface/smali/Target.smali
@@ -0,0 +1,40 @@
+# /*
+# * 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.
+# */
+#
+# package pkg;
+# public class Target {
+# public void packageMethod() {
+# System.out.println("Package method called!");
+# }
+# }
+
+.class public Lpkg/Target;
+
+.super Ljava/lang/Object;
+
+.method public constructor <init>()V
+ .locals 0
+ invoke-direct {p0}, Ljava/lang/Object;-><init>()V
+ return-void
+.end method
+
+.method packageMethod()V
+ .locals 2
+ const-string v1, "Package method called!"
+ sget-object v0, Ljava/lang/System;->out:Ljava/io/PrintStream;
+ invoke-virtual {v0, v1}, Ljava/io/PrintStream;->println(Ljava/lang/String;)V
+ return-void
+.end method
diff --git a/test/Android.run-test.mk b/test/Android.run-test.mk
index 7a5dab0..34f8838 100644
--- a/test/Android.run-test.mk
+++ b/test/Android.run-test.mk
@@ -233,11 +233,9 @@
# Disable 149-suspend-all-stress, its output is flaky (b/28988206).
# Disable 577-profile-foreign-dex (b/27454772).
-# Disable 955-methodhandles-smali until the accompanying smali change has been landed.
TEST_ART_BROKEN_ALL_TARGET_TESTS := \
149-suspend-all-stress \
577-profile-foreign-dex \
- 955-methodhandles-smali \
ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,$(TARGET_TYPES),$(RUN_TYPES),$(PREBUILD_TYPES), \
$(COMPILER_TYPES), $(RELOCATE_TYPES),$(TRACE_TYPES),$(GC_TYPES),$(JNI_TYPES), \