Merge "Use ObjPtr for reflection.cc/h/inl"
diff --git a/Android.mk b/Android.mk
index cc18660..2647268 100644
--- a/Android.mk
+++ b/Android.mk
@@ -434,12 +434,25 @@
########################################################################
# Phony target for only building what go/lem requires on target.
.PHONY: build-art-target-golem
+# Also include libartbenchmark, we always include it when running golem.
+ART_TARGET_SHARED_LIBRARY_BENCHMARK := $(TARGET_OUT_SHARED_LIBRARIES)/libartbenchmark.so
build-art-target-golem: dex2oat dalvikvm patchoat linker \
$(TARGET_OUT)/etc/public.libraries.txt \
$(ART_TARGET_DEX_DEPENDENCIES) \
$(ART_TARGET_SHARED_LIBRARY_DEPENDENCIES) \
+ $(ART_TARGET_SHARED_LIBRARY_BENCHMARK) \
$(TARGET_CORE_IMG_OUT_BASE).art \
$(TARGET_CORE_IMG_OUT_BASE)-interpreter.art
+ sed -i '/libartd.so/d' $(TARGET_OUT)/etc/public.libraries.txt
+ # remove libartd.so from public.libraries.txt because golem builds won't have it.
+
+########################################################################
+# Phony target for building what go/lem requires on host.
+.PHONY: build-art-host-golem
+# Also include libartbenchmark, we always include it when running golem.
+ART_HOST_SHARED_LIBRARY_BENCHMARK := $(ART_HOST_OUT_SHARED_LIBRARIES)/libartbenchmark.so
+build-art-host-golem: build-art-host \
+ $(ART_HOST_SHARED_LIBRARY_BENCHMARK)
########################################################################
# Rules for building all dependencies for tests.
diff --git a/benchmark/Android.bp b/benchmark/Android.bp
index a7ca279..dd19888 100644
--- a/benchmark/Android.bp
+++ b/benchmark/Android.bp
@@ -19,8 +19,10 @@
host_supported: true,
defaults: ["art_defaults", "art_debug_defaults"],
srcs: [
+ "jni_loader.cc",
"jobject-benchmark/jobject_benchmark.cc",
"jni-perf/perf_jni.cc",
+ "micro-native/micro_native.cc",
"scoped-primitive-array/scoped_primitive_array.cc",
],
shared_libs: [
diff --git a/benchmark/jni_loader.cc b/benchmark/jni_loader.cc
new file mode 100644
index 0000000..2c9f86e
--- /dev/null
+++ b/benchmark/jni_loader.cc
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2016 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>
+
+extern void register_micro_native_methods(JNIEnv* env);
+
+jint JNI_OnLoad(JavaVM* vm, void* /*reserved*/) {
+ JNIEnv* env;
+ if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
+ return -1;
+ }
+
+ // List of functions to call to register methods explicitly.
+ // Otherwise we use the regular JNI naming conventions to register implicitly.
+ register_micro_native_methods(env);
+
+ return JNI_VERSION_1_6;
+}
diff --git a/benchmark/micro-native/micro_native.cc b/benchmark/micro-native/micro_native.cc
new file mode 100644
index 0000000..43c29e2
--- /dev/null
+++ b/benchmark/micro-native/micro_native.cc
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#define LOG_TAG "NativeMethods"
+
+#define CLASS_NAME "benchmarks/MicroNative/java/NativeMethods"
+
+#include "JNIHelp.h"
+#include "JniConstants.h"
+
+static void NativeMethods_emptyJniStaticSynchronizedMethod0(JNIEnv*, jclass) { }
+static void NativeMethods_emptyJniSynchronizedMethod0(JNIEnv*, jclass) { }
+
+static JNINativeMethod gMethods_NormalOnly[] = {
+ NATIVE_METHOD(NativeMethods, emptyJniStaticSynchronizedMethod0, "()V"),
+ NATIVE_METHOD(NativeMethods, emptyJniSynchronizedMethod0, "()V"),
+};
+
+static void NativeMethods_emptyJniMethod0(JNIEnv*, jobject) { }
+static void NativeMethods_emptyJniMethod6(JNIEnv*, jobject, int, int, int, int, int, int) { }
+static void NativeMethods_emptyJniMethod6L(JNIEnv*, jobject, jobject, jarray, jarray, jobject,
+ jarray, jarray) { }
+static void NativeMethods_emptyJniStaticMethod6L(JNIEnv*, jclass, jobject, jarray, jarray, jobject,
+ jarray, jarray) { }
+
+static void NativeMethods_emptyJniStaticMethod0(JNIEnv*, jclass) { }
+static void NativeMethods_emptyJniStaticMethod6(JNIEnv*, jclass, int, int, int, int, int, int) { }
+
+static JNINativeMethod gMethods[] = {
+ NATIVE_METHOD(NativeMethods, emptyJniMethod0, "()V"),
+ NATIVE_METHOD(NativeMethods, emptyJniMethod6, "(IIIIII)V"),
+ NATIVE_METHOD(NativeMethods, emptyJniMethod6L, "(Ljava/lang/String;[Ljava/lang/String;[[ILjava/lang/Object;[Ljava/lang/Object;[[[[Ljava/lang/Object;)V"),
+ NATIVE_METHOD(NativeMethods, emptyJniStaticMethod6L, "(Ljava/lang/String;[Ljava/lang/String;[[ILjava/lang/Object;[Ljava/lang/Object;[[[[Ljava/lang/Object;)V"),
+ NATIVE_METHOD(NativeMethods, emptyJniStaticMethod0, "()V"),
+ NATIVE_METHOD(NativeMethods, emptyJniStaticMethod6, "(IIIIII)V"),
+};
+
+static void NativeMethods_emptyJniMethod0_Fast(JNIEnv*, jobject) { }
+static void NativeMethods_emptyJniMethod6_Fast(JNIEnv*, jobject, int, int, int, int, int, int) { }
+static void NativeMethods_emptyJniMethod6L_Fast(JNIEnv*, jobject, jobject, jarray, jarray, jobject,
+ jarray, jarray) { }
+static void NativeMethods_emptyJniStaticMethod6L_Fast(JNIEnv*, jclass, jobject, jarray, jarray,
+ jobject, jarray, jarray) { }
+
+static void NativeMethods_emptyJniStaticMethod0_Fast(JNIEnv*, jclass) { }
+static void NativeMethods_emptyJniStaticMethod6_Fast(JNIEnv*, jclass, int, int, int, int, int, int) { }
+
+static JNINativeMethod gMethods_Fast[] = {
+ NATIVE_METHOD(NativeMethods, emptyJniMethod0_Fast, "()V"),
+ NATIVE_METHOD(NativeMethods, emptyJniMethod6_Fast, "(IIIIII)V"),
+ NATIVE_METHOD(NativeMethods, emptyJniMethod6L_Fast, "(Ljava/lang/String;[Ljava/lang/String;[[ILjava/lang/Object;[Ljava/lang/Object;[[[[Ljava/lang/Object;)V"),
+ NATIVE_METHOD(NativeMethods, emptyJniStaticMethod6L_Fast, "(Ljava/lang/String;[Ljava/lang/String;[[ILjava/lang/Object;[Ljava/lang/Object;[[[[Ljava/lang/Object;)V"),
+ NATIVE_METHOD(NativeMethods, emptyJniStaticMethod0_Fast, "()V"),
+ NATIVE_METHOD(NativeMethods, emptyJniStaticMethod6_Fast, "(IIIIII)V"),
+};
+
+static void NativeMethods_emptyJniStaticMethod0_Critical() { }
+static void NativeMethods_emptyJniStaticMethod6_Critical(int, int, int, int, int, int) { }
+
+static JNINativeMethod gMethods_Critical[] = {
+ NATIVE_METHOD(NativeMethods, emptyJniStaticMethod0_Critical, "()V"),
+ NATIVE_METHOD(NativeMethods, emptyJniStaticMethod6_Critical, "(IIIIII)V"),
+};
+
+void register_micro_native_methods(JNIEnv* env) {
+ jniRegisterNativeMethods(env, CLASS_NAME, gMethods_NormalOnly, NELEM(gMethods_NormalOnly));
+ jniRegisterNativeMethods(env, CLASS_NAME, gMethods, NELEM(gMethods));
+ jniRegisterNativeMethods(env, CLASS_NAME, gMethods_Fast, NELEM(gMethods_Fast));
+ jniRegisterNativeMethods(env, CLASS_NAME, gMethods_Critical, NELEM(gMethods_Critical));
+}
diff --git a/compiler/image_writer.cc b/compiler/image_writer.cc
index ad881b7..6b5758b 100644
--- a/compiler/image_writer.cc
+++ b/compiler/image_writer.cc
@@ -45,6 +45,7 @@
#include "gc/space/space-inl.h"
#include "globals.h"
#include "image.h"
+#include "imt_conflict_table.h"
#include "intern_table.h"
#include "linear_alloc.h"
#include "lock_word.h"
diff --git a/compiler/optimizing/instruction_builder.cc b/compiler/optimizing/instruction_builder.cc
index 139daa7..3b08d9f 100644
--- a/compiler/optimizing/instruction_builder.cc
+++ b/compiler/optimizing/instruction_builder.cc
@@ -21,6 +21,7 @@
#include "class_linker.h"
#include "dex_instruction-inl.h"
#include "driver/compiler_options.h"
+#include "imtable-inl.h"
#include "scoped_thread_state_change.h"
namespace art {
@@ -895,7 +896,7 @@
dex_pc,
method_idx,
resolved_method,
- resolved_method->GetImtIndex());
+ ImTable::GetImtIndex(resolved_method));
}
return HandleInvoke(invoke,
diff --git a/runtime/arch/stub_test.cc b/runtime/arch/stub_test.cc
index 507dbf0..3424e3c 100644
--- a/runtime/arch/stub_test.cc
+++ b/runtime/arch/stub_test.cc
@@ -22,6 +22,7 @@
#include "class_linker-inl.h"
#include "common_runtime_test.h"
#include "entrypoints/quick/quick_entrypoints_enum.h"
+#include "imt_conflict_table.h"
#include "linear_alloc.h"
#include "mirror/class-inl.h"
#include "mirror/string-inl.h"
diff --git a/runtime/art_method-inl.h b/runtime/art_method-inl.h
index 9b4b38a..73cce5e 100644
--- a/runtime/art_method-inl.h
+++ b/runtime/art_method-inl.h
@@ -123,10 +123,6 @@
return dex_method_index_;
}
-inline uint32_t ArtMethod::GetImtIndex() {
- return GetDexMethodIndex() % ImTable::kSize;
-}
-
inline ArtMethod** ArtMethod::GetDexCacheResolvedMethods(PointerSize pointer_size) {
return GetNativePointer<ArtMethod**>(DexCacheResolvedMethodsOffset(pointer_size),
pointer_size);
diff --git a/runtime/art_method.h b/runtime/art_method.h
index b1baccd..3d2db69 100644
--- a/runtime/art_method.h
+++ b/runtime/art_method.h
@@ -34,6 +34,7 @@
namespace art {
template<class T> class Handle;
+class ImtConflictTable;
union JValue;
class OatQuickMethodHeader;
class ProfilingInfo;
@@ -48,175 +49,6 @@
class PointerArray;
} // namespace mirror
-// Table to resolve IMT conflicts at runtime. The table is attached to
-// the jni entrypoint of IMT conflict ArtMethods.
-// The table contains a list of pairs of { interface_method, implementation_method }
-// with the last entry being null to make an assembly implementation of a lookup
-// faster.
-class ImtConflictTable {
- enum MethodIndex {
- kMethodInterface,
- kMethodImplementation,
- kMethodCount, // Number of elements in enum.
- };
-
- public:
- // Build a new table copying `other` and adding the new entry formed of
- // the pair { `interface_method`, `implementation_method` }
- ImtConflictTable(ImtConflictTable* other,
- ArtMethod* interface_method,
- ArtMethod* implementation_method,
- PointerSize pointer_size) {
- const size_t count = other->NumEntries(pointer_size);
- for (size_t i = 0; i < count; ++i) {
- SetInterfaceMethod(i, pointer_size, other->GetInterfaceMethod(i, pointer_size));
- SetImplementationMethod(i, pointer_size, other->GetImplementationMethod(i, pointer_size));
- }
- SetInterfaceMethod(count, pointer_size, interface_method);
- SetImplementationMethod(count, pointer_size, implementation_method);
- // Add the null marker.
- SetInterfaceMethod(count + 1, pointer_size, nullptr);
- SetImplementationMethod(count + 1, pointer_size, nullptr);
- }
-
- // num_entries excludes the header.
- ImtConflictTable(size_t num_entries, PointerSize pointer_size) {
- SetInterfaceMethod(num_entries, pointer_size, nullptr);
- SetImplementationMethod(num_entries, pointer_size, nullptr);
- }
-
- // Set an entry at an index.
- void SetInterfaceMethod(size_t index, PointerSize pointer_size, ArtMethod* method) {
- SetMethod(index * kMethodCount + kMethodInterface, pointer_size, method);
- }
-
- void SetImplementationMethod(size_t index, PointerSize pointer_size, ArtMethod* method) {
- SetMethod(index * kMethodCount + kMethodImplementation, pointer_size, method);
- }
-
- ArtMethod* GetInterfaceMethod(size_t index, PointerSize pointer_size) const {
- return GetMethod(index * kMethodCount + kMethodInterface, pointer_size);
- }
-
- ArtMethod* GetImplementationMethod(size_t index, PointerSize pointer_size) const {
- return GetMethod(index * kMethodCount + kMethodImplementation, pointer_size);
- }
-
- // Return true if two conflict tables are the same.
- bool Equals(ImtConflictTable* other, PointerSize pointer_size) const {
- size_t num = NumEntries(pointer_size);
- if (num != other->NumEntries(pointer_size)) {
- return false;
- }
- for (size_t i = 0; i < num; ++i) {
- if (GetInterfaceMethod(i, pointer_size) != other->GetInterfaceMethod(i, pointer_size) ||
- GetImplementationMethod(i, pointer_size) !=
- other->GetImplementationMethod(i, pointer_size)) {
- return false;
- }
- }
- return true;
- }
-
- // Visit all of the entries.
- // NO_THREAD_SAFETY_ANALYSIS for calling with held locks. Visitor is passed a pair of ArtMethod*
- // and also returns one. The order is <interface, implementation>.
- template<typename Visitor>
- void Visit(const Visitor& visitor, PointerSize pointer_size) NO_THREAD_SAFETY_ANALYSIS {
- uint32_t table_index = 0;
- for (;;) {
- ArtMethod* interface_method = GetInterfaceMethod(table_index, pointer_size);
- if (interface_method == nullptr) {
- break;
- }
- ArtMethod* implementation_method = GetImplementationMethod(table_index, pointer_size);
- auto input = std::make_pair(interface_method, implementation_method);
- std::pair<ArtMethod*, ArtMethod*> updated = visitor(input);
- if (input.first != updated.first) {
- SetInterfaceMethod(table_index, pointer_size, updated.first);
- }
- if (input.second != updated.second) {
- SetImplementationMethod(table_index, pointer_size, updated.second);
- }
- ++table_index;
- }
- }
-
- // Lookup the implementation ArtMethod associated to `interface_method`. Return null
- // if not found.
- ArtMethod* Lookup(ArtMethod* interface_method, PointerSize pointer_size) const {
- uint32_t table_index = 0;
- for (;;) {
- ArtMethod* current_interface_method = GetInterfaceMethod(table_index, pointer_size);
- if (current_interface_method == nullptr) {
- break;
- }
- if (current_interface_method == interface_method) {
- return GetImplementationMethod(table_index, pointer_size);
- }
- ++table_index;
- }
- return nullptr;
- }
-
- // Compute the number of entries in this table.
- size_t NumEntries(PointerSize pointer_size) const {
- uint32_t table_index = 0;
- while (GetInterfaceMethod(table_index, pointer_size) != nullptr) {
- ++table_index;
- }
- return table_index;
- }
-
- // Compute the size in bytes taken by this table.
- size_t ComputeSize(PointerSize pointer_size) const {
- // Add the end marker.
- return ComputeSize(NumEntries(pointer_size), pointer_size);
- }
-
- // Compute the size in bytes needed for copying the given `table` and add
- // one more entry.
- static size_t ComputeSizeWithOneMoreEntry(ImtConflictTable* table, PointerSize pointer_size) {
- return table->ComputeSize(pointer_size) + EntrySize(pointer_size);
- }
-
- // Compute size with a fixed number of entries.
- static size_t ComputeSize(size_t num_entries, PointerSize pointer_size) {
- return (num_entries + 1) * EntrySize(pointer_size); // Add one for null terminator.
- }
-
- static size_t EntrySize(PointerSize pointer_size) {
- return static_cast<size_t>(pointer_size) * static_cast<size_t>(kMethodCount);
- }
-
- private:
- ArtMethod* GetMethod(size_t index, PointerSize pointer_size) const {
- if (pointer_size == PointerSize::k64) {
- return reinterpret_cast<ArtMethod*>(static_cast<uintptr_t>(data64_[index]));
- } else {
- return reinterpret_cast<ArtMethod*>(static_cast<uintptr_t>(data32_[index]));
- }
- }
-
- void SetMethod(size_t index, PointerSize pointer_size, ArtMethod* method) {
- if (pointer_size == PointerSize::k64) {
- data64_[index] = dchecked_integral_cast<uint64_t>(reinterpret_cast<uintptr_t>(method));
- } else {
- data32_[index] = dchecked_integral_cast<uint32_t>(reinterpret_cast<uintptr_t>(method));
- }
- }
-
- // Array of entries that the assembly stubs will iterate over. Note that this is
- // not fixed size, and we allocate data prior to calling the constructor
- // of ImtConflictTable.
- union {
- uint32_t data32_[0];
- uint64_t data64_[0];
- };
-
- DISALLOW_COPY_AND_ASSIGN(ImtConflictTable);
-};
-
class ArtMethod FINAL {
public:
ArtMethod() : access_flags_(0), dex_code_item_offset_(0), dex_method_index_(0),
@@ -428,8 +260,6 @@
ALWAYS_INLINE uint32_t GetDexMethodIndex() REQUIRES_SHARED(Locks::mutator_lock_);
- ALWAYS_INLINE uint32_t GetImtIndex() REQUIRES_SHARED(Locks::mutator_lock_);
-
void SetDexMethodIndex(uint32_t new_idx) {
// Not called within a transaction.
dex_method_index_ = new_idx;
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index eb38a8c..48550f3 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -56,6 +56,8 @@
#include "gc/space/image_space.h"
#include "handle_scope-inl.h"
#include "image-inl.h"
+#include "imt_conflict_table.h"
+#include "imtable-inl.h"
#include "intern_table.h"
#include "interpreter/interpreter.h"
#include "jit/jit.h"
@@ -6269,7 +6271,7 @@
// or interface methods in the IMT here they will not create extra conflicts since we compare
// names and signatures in SetIMTRef.
ArtMethod* interface_method = interface->GetVirtualMethod(j, image_pointer_size_);
- const uint32_t imt_index = interface_method->GetImtIndex();
+ const uint32_t imt_index = ImTable::GetImtIndex(interface_method);
// There is only any conflicts if all of the interface methods for an IMT slot don't have
// the same implementation method, keep track of this to avoid creating a conflict table in
@@ -6323,7 +6325,7 @@
}
DCHECK(implementation_method != nullptr);
ArtMethod* interface_method = interface->GetVirtualMethod(j, image_pointer_size_);
- const uint32_t imt_index = interface_method->GetImtIndex();
+ const uint32_t imt_index = ImTable::GetImtIndex(interface_method);
if (!imt[imt_index]->IsRuntimeMethod() ||
imt[imt_index] == unimplemented_method ||
imt[imt_index] == imt_conflict_method) {
@@ -6782,7 +6784,7 @@
auto* interface_method = iftable->GetInterface(i)->GetVirtualMethod(j, image_pointer_size_);
MethodNameAndSignatureComparator interface_name_comparator(
interface_method->GetInterfaceMethodIfProxy(image_pointer_size_));
- uint32_t imt_index = interface_method->GetImtIndex();
+ uint32_t imt_index = ImTable::GetImtIndex(interface_method);
ArtMethod** imt_ptr = &out_imt[imt_index];
// For each method listed in the interface's method list, find the
// matching method in our class's method list. We want to favor the
diff --git a/runtime/dex_file_annotations.cc b/runtime/dex_file_annotations.cc
index c3cf53b..789a5bd 100644
--- a/runtime/dex_file_annotations.cc
+++ b/runtime/dex_file_annotations.cc
@@ -1027,6 +1027,66 @@
annotation_class);
}
+bool GetParametersMetadataForMethod(ArtMethod* method,
+ MutableHandle<mirror::ObjectArray<mirror::String>>* names,
+ MutableHandle<mirror::IntArray>* access_flags) {
+ const DexFile::AnnotationSetItem::AnnotationSetItem* annotation_set =
+ FindAnnotationSetForMethod(method);
+ if (annotation_set == nullptr) {
+ return false;
+ }
+
+ const DexFile* dex_file = method->GetDexFile();
+ const DexFile::AnnotationItem* annotation_item =
+ SearchAnnotationSet(*dex_file,
+ annotation_set,
+ "Ldalvik/annotation/MethodParameters;",
+ DexFile::kDexVisibilitySystem);
+ if (annotation_item == nullptr) {
+ return false;
+ }
+
+ StackHandleScope<5> hs(Thread::Current());
+
+ // Extract the parameters' names String[].
+ mirror::Class* string_class = mirror::String::GetJavaLangString();
+ Handle<mirror::Class> string_array_class(hs.NewHandle(
+ Runtime::Current()->GetClassLinker()->FindArrayClass(Thread::Current(), &string_class)));
+ if (UNLIKELY(string_array_class.Get() == nullptr)) {
+ return false;
+ }
+
+ Handle<mirror::Class> klass = hs.NewHandle(method->GetDeclaringClass());
+ Handle<mirror::Object> names_obj =
+ hs.NewHandle(GetAnnotationValue(klass,
+ annotation_item,
+ "names",
+ string_array_class,
+ DexFile::kDexAnnotationArray));
+ if (names_obj.Get() == nullptr) {
+ return false;
+ }
+
+ // Extract the parameters' access flags int[].
+ Handle<mirror::Class> int_array_class(hs.NewHandle(mirror::IntArray::GetArrayClass()));
+ if (UNLIKELY(int_array_class.Get() == nullptr)) {
+ return false;
+ }
+ Handle<mirror::Object> access_flags_obj =
+ hs.NewHandle(GetAnnotationValue(klass,
+ annotation_item,
+ "accessFlags",
+ int_array_class,
+ DexFile::kDexAnnotationArray));
+ if (access_flags_obj.Get() == nullptr) {
+ return false;
+ }
+
+ names->Assign(names_obj.Get()->AsObjectArray<mirror::String>());
+ access_flags->Assign(access_flags_obj.Get()->AsIntArray());
+ return true;
+}
+
mirror::ObjectArray<mirror::String>* GetSignatureAnnotationForMethod(ArtMethod* method) {
const DexFile::AnnotationSetItem* annotation_set = FindAnnotationSetForMethod(method);
if (annotation_set == nullptr) {
diff --git a/runtime/dex_file_annotations.h b/runtime/dex_file_annotations.h
index 7b4e856..c66c5bd 100644
--- a/runtime/dex_file_annotations.h
+++ b/runtime/dex_file_annotations.h
@@ -30,6 +30,7 @@
class ArtField;
class ArtMethod;
class ClassLinker;
+template<class T> class MutableHandle;
namespace annotations {
@@ -58,6 +59,10 @@
uint32_t parameter_idx,
Handle<mirror::Class> annotation_class)
REQUIRES_SHARED(Locks::mutator_lock_);
+bool GetParametersMetadataForMethod(ArtMethod* method,
+ MutableHandle<mirror::ObjectArray<mirror::String>>* names,
+ MutableHandle<mirror::IntArray>* access_flags)
+ REQUIRES_SHARED(Locks::mutator_lock_);
mirror::ObjectArray<mirror::String>* GetSignatureAnnotationForMethod(ArtMethod* method)
REQUIRES_SHARED(Locks::mutator_lock_);
bool IsMethodAnnotationPresent(ArtMethod* method, Handle<mirror::Class> annotation_class,
diff --git a/runtime/entrypoints/entrypoint_utils-inl.h b/runtime/entrypoints/entrypoint_utils-inl.h
index 14110c2..99b8805 100644
--- a/runtime/entrypoints/entrypoint_utils-inl.h
+++ b/runtime/entrypoints/entrypoint_utils-inl.h
@@ -26,6 +26,8 @@
#include "dex_file.h"
#include "entrypoints/quick/callee_save_frame.h"
#include "handle_scope-inl.h"
+#include "imt_conflict_table.h"
+#include "imtable-inl.h"
#include "indirect_reference_table.h"
#include "invoke_type.h"
#include "jni_internal.h"
@@ -612,7 +614,7 @@
UNREACHABLE();
}
case kInterface: {
- uint32_t imt_index = resolved_method->GetImtIndex();
+ uint32_t imt_index = ImTable::GetImtIndex(resolved_method);
PointerSize pointer_size = class_linker->GetImagePointerSize();
ArtMethod* imt_method = (*this_object)->GetClass()->GetImt(pointer_size)->
Get(imt_index, pointer_size);
diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
index fcbd834..cfd948e 100644
--- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
@@ -23,6 +23,8 @@
#include "entrypoints/entrypoint_utils-inl.h"
#include "entrypoints/runtime_asm_entrypoints.h"
#include "gc/accounting/card_table-inl.h"
+#include "imt_conflict_table.h"
+#include "imtable-inl.h"
#include "interpreter/interpreter.h"
#include "linear_alloc.h"
#include "method_reference.h"
@@ -2239,7 +2241,8 @@
if (LIKELY(interface_method->GetDexMethodIndex() != DexFile::kDexNoIndex)) {
// If the dex cache already resolved the interface method, look whether we have
// a match in the ImtConflictTable.
- ArtMethod* conflict_method = imt->Get(interface_method->GetImtIndex(), kRuntimePointerSize);
+ ArtMethod* conflict_method = imt->Get(ImTable::GetImtIndex(interface_method),
+ kRuntimePointerSize);
if (LIKELY(conflict_method->IsRuntimeMethod())) {
ImtConflictTable* current_table = conflict_method->GetImtConflictTable(kRuntimePointerSize);
DCHECK(current_table != nullptr);
@@ -2291,7 +2294,7 @@
// We arrive here if we have found an implementation, and it is not in the ImtConflictTable.
// We create a new table with the new pair { interface_method, method }.
- uint32_t imt_index = interface_method->GetImtIndex();
+ uint32_t imt_index = ImTable::GetImtIndex(interface_method);
ArtMethod* conflict_method = imt->Get(imt_index, kRuntimePointerSize);
if (conflict_method->IsRuntimeMethod()) {
ArtMethod* new_conflict_method = Runtime::Current()->GetClassLinker()->AddMethodToConflictTable(
diff --git a/runtime/image-inl.h b/runtime/image-inl.h
index 669649e..da18ae5 100644
--- a/runtime/image-inl.h
+++ b/runtime/image-inl.h
@@ -20,6 +20,7 @@
#include "image.h"
#include "art_method.h"
+#include "imt_conflict_table.h"
#include "imtable.h"
#include "read_barrier-inl.h"
diff --git a/runtime/imt_conflict_table.h b/runtime/imt_conflict_table.h
new file mode 100644
index 0000000..fdd10fe
--- /dev/null
+++ b/runtime/imt_conflict_table.h
@@ -0,0 +1,201 @@
+/*
+ * Copyright (C) 2016 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_IMT_CONFLICT_TABLE_H_
+#define ART_RUNTIME_IMT_CONFLICT_TABLE_H_
+
+#include <cstddef>
+
+#include "base/casts.h"
+#include "base/enums.h"
+#include "base/macros.h"
+
+namespace art {
+
+class ArtMethod;
+
+// Table to resolve IMT conflicts at runtime. The table is attached to
+// the jni entrypoint of IMT conflict ArtMethods.
+// The table contains a list of pairs of { interface_method, implementation_method }
+// with the last entry being null to make an assembly implementation of a lookup
+// faster.
+class ImtConflictTable {
+ enum MethodIndex {
+ kMethodInterface,
+ kMethodImplementation,
+ kMethodCount, // Number of elements in enum.
+ };
+
+ public:
+ // Build a new table copying `other` and adding the new entry formed of
+ // the pair { `interface_method`, `implementation_method` }
+ ImtConflictTable(ImtConflictTable* other,
+ ArtMethod* interface_method,
+ ArtMethod* implementation_method,
+ PointerSize pointer_size) {
+ const size_t count = other->NumEntries(pointer_size);
+ for (size_t i = 0; i < count; ++i) {
+ SetInterfaceMethod(i, pointer_size, other->GetInterfaceMethod(i, pointer_size));
+ SetImplementationMethod(i, pointer_size, other->GetImplementationMethod(i, pointer_size));
+ }
+ SetInterfaceMethod(count, pointer_size, interface_method);
+ SetImplementationMethod(count, pointer_size, implementation_method);
+ // Add the null marker.
+ SetInterfaceMethod(count + 1, pointer_size, nullptr);
+ SetImplementationMethod(count + 1, pointer_size, nullptr);
+ }
+
+ // num_entries excludes the header.
+ ImtConflictTable(size_t num_entries, PointerSize pointer_size) {
+ SetInterfaceMethod(num_entries, pointer_size, nullptr);
+ SetImplementationMethod(num_entries, pointer_size, nullptr);
+ }
+
+ // Set an entry at an index.
+ void SetInterfaceMethod(size_t index, PointerSize pointer_size, ArtMethod* method) {
+ SetMethod(index * kMethodCount + kMethodInterface, pointer_size, method);
+ }
+
+ void SetImplementationMethod(size_t index, PointerSize pointer_size, ArtMethod* method) {
+ SetMethod(index * kMethodCount + kMethodImplementation, pointer_size, method);
+ }
+
+ ArtMethod* GetInterfaceMethod(size_t index, PointerSize pointer_size) const {
+ return GetMethod(index * kMethodCount + kMethodInterface, pointer_size);
+ }
+
+ ArtMethod* GetImplementationMethod(size_t index, PointerSize pointer_size) const {
+ return GetMethod(index * kMethodCount + kMethodImplementation, pointer_size);
+ }
+
+ // Return true if two conflict tables are the same.
+ bool Equals(ImtConflictTable* other, PointerSize pointer_size) const {
+ size_t num = NumEntries(pointer_size);
+ if (num != other->NumEntries(pointer_size)) {
+ return false;
+ }
+ for (size_t i = 0; i < num; ++i) {
+ if (GetInterfaceMethod(i, pointer_size) != other->GetInterfaceMethod(i, pointer_size) ||
+ GetImplementationMethod(i, pointer_size) !=
+ other->GetImplementationMethod(i, pointer_size)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ // Visit all of the entries.
+ // NO_THREAD_SAFETY_ANALYSIS for calling with held locks. Visitor is passed a pair of ArtMethod*
+ // and also returns one. The order is <interface, implementation>.
+ template<typename Visitor>
+ void Visit(const Visitor& visitor, PointerSize pointer_size) NO_THREAD_SAFETY_ANALYSIS {
+ uint32_t table_index = 0;
+ for (;;) {
+ ArtMethod* interface_method = GetInterfaceMethod(table_index, pointer_size);
+ if (interface_method == nullptr) {
+ break;
+ }
+ ArtMethod* implementation_method = GetImplementationMethod(table_index, pointer_size);
+ auto input = std::make_pair(interface_method, implementation_method);
+ std::pair<ArtMethod*, ArtMethod*> updated = visitor(input);
+ if (input.first != updated.first) {
+ SetInterfaceMethod(table_index, pointer_size, updated.first);
+ }
+ if (input.second != updated.second) {
+ SetImplementationMethod(table_index, pointer_size, updated.second);
+ }
+ ++table_index;
+ }
+ }
+
+ // Lookup the implementation ArtMethod associated to `interface_method`. Return null
+ // if not found.
+ ArtMethod* Lookup(ArtMethod* interface_method, PointerSize pointer_size) const {
+ uint32_t table_index = 0;
+ for (;;) {
+ ArtMethod* current_interface_method = GetInterfaceMethod(table_index, pointer_size);
+ if (current_interface_method == nullptr) {
+ break;
+ }
+ if (current_interface_method == interface_method) {
+ return GetImplementationMethod(table_index, pointer_size);
+ }
+ ++table_index;
+ }
+ return nullptr;
+ }
+
+ // Compute the number of entries in this table.
+ size_t NumEntries(PointerSize pointer_size) const {
+ uint32_t table_index = 0;
+ while (GetInterfaceMethod(table_index, pointer_size) != nullptr) {
+ ++table_index;
+ }
+ return table_index;
+ }
+
+ // Compute the size in bytes taken by this table.
+ size_t ComputeSize(PointerSize pointer_size) const {
+ // Add the end marker.
+ return ComputeSize(NumEntries(pointer_size), pointer_size);
+ }
+
+ // Compute the size in bytes needed for copying the given `table` and add
+ // one more entry.
+ static size_t ComputeSizeWithOneMoreEntry(ImtConflictTable* table, PointerSize pointer_size) {
+ return table->ComputeSize(pointer_size) + EntrySize(pointer_size);
+ }
+
+ // Compute size with a fixed number of entries.
+ static size_t ComputeSize(size_t num_entries, PointerSize pointer_size) {
+ return (num_entries + 1) * EntrySize(pointer_size); // Add one for null terminator.
+ }
+
+ static size_t EntrySize(PointerSize pointer_size) {
+ return static_cast<size_t>(pointer_size) * static_cast<size_t>(kMethodCount);
+ }
+
+ private:
+ ArtMethod* GetMethod(size_t index, PointerSize pointer_size) const {
+ if (pointer_size == PointerSize::k64) {
+ return reinterpret_cast<ArtMethod*>(static_cast<uintptr_t>(data64_[index]));
+ } else {
+ return reinterpret_cast<ArtMethod*>(static_cast<uintptr_t>(data32_[index]));
+ }
+ }
+
+ void SetMethod(size_t index, PointerSize pointer_size, ArtMethod* method) {
+ if (pointer_size == PointerSize::k64) {
+ data64_[index] = dchecked_integral_cast<uint64_t>(reinterpret_cast<uintptr_t>(method));
+ } else {
+ data32_[index] = dchecked_integral_cast<uint32_t>(reinterpret_cast<uintptr_t>(method));
+ }
+ }
+
+ // Array of entries that the assembly stubs will iterate over. Note that this is
+ // not fixed size, and we allocate data prior to calling the constructor
+ // of ImtConflictTable.
+ union {
+ uint32_t data32_[0];
+ uint64_t data64_[0];
+ };
+
+ DISALLOW_COPY_AND_ASSIGN(ImtConflictTable);
+};
+
+} // namespace art
+
+#endif // ART_RUNTIME_IMT_CONFLICT_TABLE_H_
diff --git a/runtime/imtable-inl.h b/runtime/imtable-inl.h
new file mode 100644
index 0000000..0cb9b5e
--- /dev/null
+++ b/runtime/imtable-inl.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2016 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_IMTABLE_INL_H_
+#define ART_RUNTIME_IMTABLE_INL_H_
+
+#include "imtable.h"
+
+#include "art_method-inl.h"
+
+namespace art {
+
+inline uint32_t ImTable::GetBaseImtHash(ArtMethod* method) REQUIRES_SHARED(Locks::mutator_lock_) {
+ return method->GetDexMethodIndex();
+}
+
+inline uint32_t ImTable::GetImtIndex(ArtMethod* method) {
+ return GetBaseImtHash(method) % ImTable::kSize;
+}
+
+} // namespace art
+
+#endif // ART_RUNTIME_IMTABLE_INL_H_
+
diff --git a/runtime/imtable.h b/runtime/imtable.h
index 2416621..6df890d 100644
--- a/runtime/imtable.h
+++ b/runtime/imtable.h
@@ -21,9 +21,13 @@
#error IMT_SIZE not defined
#endif
+#include "base/enums.h"
+#include "base/macros.h"
+
namespace art {
class ArtMethod;
+class DexFile;
class ImTable {
public:
@@ -69,6 +73,19 @@
constexpr static size_t SizeInBytes(PointerSize pointer_size) {
return kSize * static_cast<size_t>(pointer_size);
}
+
+ // Converts a method to the base hash used in GetImtIndex.
+ ALWAYS_INLINE static inline uint32_t GetBaseImtHash(ArtMethod* method)
+ REQUIRES_SHARED(Locks::mutator_lock_);
+ ALWAYS_INLINE static inline uint32_t GetBaseImtHash(const DexFile* dex_file, uint32_t method_idx)
+ REQUIRES_SHARED(Locks::mutator_lock_);
+
+ // The (complete) hashing scheme to map an ArtMethod to a slot in the Interface Method Table
+ // (IMT).
+ ALWAYS_INLINE static inline uint32_t GetImtIndex(ArtMethod* method)
+ REQUIRES_SHARED(Locks::mutator_lock_);
+ ALWAYS_INLINE static inline uint32_t GetImtIndex(const DexFile* dex_file, uint32_t method_idx)
+ REQUIRES_SHARED(Locks::mutator_lock_);
};
} // namespace art
diff --git a/runtime/native/java_lang_reflect_Executable.cc b/runtime/native/java_lang_reflect_Executable.cc
index 8fcf6ac..f345c09 100644
--- a/runtime/native/java_lang_reflect_Executable.cc
+++ b/runtime/native/java_lang_reflect_Executable.cc
@@ -18,8 +18,10 @@
#include "art_method-inl.h"
#include "dex_file_annotations.h"
+#include "handle.h"
#include "jni_internal.h"
#include "mirror/class-inl.h"
+#include "mirror/method.h"
#include "mirror/object-inl.h"
#include "mirror/object_array-inl.h"
#include "reflection.h"
@@ -43,8 +45,8 @@
}
static jobject Executable_getAnnotationNative(JNIEnv* env,
- jobject javaMethod,
- jclass annotationType) {
+ jobject javaMethod,
+ jclass annotationType) {
ScopedFastNativeObjectAccess soa(env);
StackHandleScope<1> hs(soa.Self());
ArtMethod* method = ArtMethod::FromReflectedMethod(soa, javaMethod);
@@ -77,9 +79,107 @@
}
}
+static jobjectArray Executable_getParameters0(JNIEnv* env, jobject javaMethod) {
+ ScopedFastNativeObjectAccess soa(env);
+ Thread* self = soa.Self();
+ StackHandleScope<8> hs(self);
+
+ Handle<mirror::Method> executable = hs.NewHandle(soa.Decode<mirror::Method*>(javaMethod));
+ ArtMethod* art_method = executable.Get()->GetArtMethod();
+ if (art_method->GetDeclaringClass()->IsProxyClass()) {
+ return nullptr;
+ }
+
+ // Find the MethodParameters system annotation.
+ MutableHandle<mirror::ObjectArray<mirror::String>> names =
+ hs.NewHandle<mirror::ObjectArray<mirror::String>>(nullptr);
+ MutableHandle<mirror::IntArray> access_flags = hs.NewHandle<mirror::IntArray>(nullptr);
+ if (!annotations::GetParametersMetadataForMethod(art_method, &names, &access_flags)) {
+ return nullptr;
+ }
+
+ // Validate the MethodParameters system annotation data.
+ if (UNLIKELY(names.Get() == nullptr || access_flags.Get() == nullptr)) {
+ ThrowIllegalArgumentException(
+ StringPrintf("Missing parameter metadata for names or access flags for %s",
+ PrettyMethod(art_method).c_str()).c_str());
+ return nullptr;
+ }
+
+ // Check array sizes match each other
+ int32_t names_count = names.Get()->GetLength();
+ int32_t access_flags_count = access_flags.Get()->GetLength();
+ if (names_count != access_flags_count) {
+ ThrowIllegalArgumentException(
+ StringPrintf(
+ "Inconsistent parameter metadata for %s. names length: %d, access flags length: %d",
+ PrettyMethod(art_method).c_str(),
+ names_count,
+ access_flags_count).c_str());
+ return nullptr;
+ }
+
+ // Instantiate a Parameter[] to hold the result.
+ Handle<mirror::Class> parameter_array_class =
+ hs.NewHandle(
+ soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_reflect_Parameter__array));
+ Handle<mirror::ObjectArray<mirror::Object>> parameter_array =
+ hs.NewHandle(
+ mirror::ObjectArray<mirror::Object>::Alloc(self,
+ parameter_array_class.Get(),
+ names_count));
+ if (UNLIKELY(parameter_array.Get() == nullptr)) {
+ self->AssertPendingException();
+ return nullptr;
+ }
+
+ Handle<mirror::Class> parameter_class =
+ hs.NewHandle(soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_reflect_Parameter));
+ ArtMethod* parameter_init =
+ soa.DecodeMethod(WellKnownClasses::java_lang_reflect_Parameter_init);
+
+ // Mutable handles used in the loop below to ensure cleanup without scaling the number of
+ // handles by the number of parameters.
+ MutableHandle<mirror::String> name = hs.NewHandle<mirror::String>(nullptr);
+ MutableHandle<mirror::Object> parameter = hs.NewHandle<mirror::Object>(nullptr);
+
+ // Populate the Parameter[] to return.
+ for (int32_t parameter_index = 0; parameter_index < names_count; parameter_index++) {
+ name.Assign(names.Get()->Get(parameter_index));
+ int32_t modifiers = access_flags.Get()->Get(parameter_index);
+
+ // Allocate / initialize the Parameter to add to parameter_array.
+ parameter.Assign(parameter_class->AllocObject(self));
+ if (UNLIKELY(parameter.Get() == nullptr)) {
+ self->AssertPendingOOMException();
+ return nullptr;
+ }
+
+ uint32_t args[5] = { PointerToLowMemUInt32(parameter.Get()),
+ PointerToLowMemUInt32(name.Get()),
+ static_cast<uint32_t>(modifiers),
+ PointerToLowMemUInt32(executable.Get()),
+ static_cast<uint32_t>(parameter_index)
+ };
+ JValue result;
+ static const char* method_signature = "VLILI"; // return + parameter types
+ parameter_init->Invoke(self, args, sizeof(args), &result, method_signature);
+ if (UNLIKELY(self->IsExceptionPending())) {
+ return nullptr;
+ }
+
+ // Store the Parameter in the Parameter[].
+ parameter_array.Get()->Set(parameter_index, parameter.Get());
+ if (UNLIKELY(self->IsExceptionPending())) {
+ return nullptr;
+ }
+ }
+ return soa.AddLocalReference<jobjectArray>(parameter_array.Get());
+}
+
static jboolean Executable_isAnnotationPresentNative(JNIEnv* env,
- jobject javaMethod,
- jclass annotationType) {
+ jobject javaMethod,
+ jclass annotationType) {
ScopedFastNativeObjectAccess soa(env);
ArtMethod* method = ArtMethod::FromReflectedMethod(soa, javaMethod);
if (method->GetDeclaringClass()->IsProxyClass()) {
@@ -96,6 +196,7 @@
NATIVE_METHOD(Executable, getDeclaredAnnotationsNative, "!()[Ljava/lang/annotation/Annotation;"),
NATIVE_METHOD(Executable, getParameterAnnotationsNative,
"!()[[Ljava/lang/annotation/Annotation;"),
+ NATIVE_METHOD(Executable, getParameters0, "!()[Ljava/lang/reflect/Parameter;"),
NATIVE_METHOD(Executable, getSignatureAnnotation, "!()[Ljava/lang/String;"),
NATIVE_METHOD(Executable, isAnnotationPresentNative, "!(Ljava/lang/Class;)Z"),
};
diff --git a/runtime/reference_table.cc b/runtime/reference_table.cc
index f04d41d..0be79ef 100644
--- a/runtime/reference_table.cc
+++ b/runtime/reference_table.cc
@@ -192,6 +192,13 @@
} else {
StringAppendF(&extras, " \"%.16s... (%d chars)", utf8.c_str(), s->GetLength());
}
+ } else if (ref->IsReferenceInstance()) {
+ mirror::Object* referent = ref->AsReference()->GetReferent();
+ if (referent == nullptr) {
+ extras = " (referent is null)";
+ } else {
+ extras = StringPrintf(" (referent is a %s)", PrettyTypeOf(referent).c_str());
+ }
}
os << StringPrintf(" %5d: ", idx) << ref << " " << className << extras << "\n";
}
diff --git a/runtime/reference_table_test.cc b/runtime/reference_table_test.cc
index fae8e72..819e17a 100644
--- a/runtime/reference_table_test.cc
+++ b/runtime/reference_table_test.cc
@@ -16,11 +16,15 @@
#include "reference_table.h"
+#include "class_linker.h"
#include "common_runtime_test.h"
+#include "handle_scope-inl.h"
#include "mirror/array-inl.h"
#include "mirror/class-inl.h"
+#include "mirror/class_loader.h"
#include "mirror/string.h"
#include "primitive.h"
+#include "runtime.h"
#include "scoped_thread_state_change.h"
#include "thread-inl.h"
@@ -28,6 +32,39 @@
class ReferenceTableTest : public CommonRuntimeTest {};
+static mirror::Object* CreateWeakReference(mirror::Object* referent)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ Thread* self = Thread::Current();
+ ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+
+ StackHandleScope<3> scope(self);
+ Handle<mirror::Object> h_referent(scope.NewHandle<mirror::Object>(referent));
+
+ Handle<mirror::Class> h_ref_class(scope.NewHandle<mirror::Class>(
+ class_linker->FindClass(self,
+ "Ljava/lang/ref/WeakReference;",
+ ScopedNullHandle<mirror::ClassLoader>())));
+ CHECK(h_ref_class.Get() != nullptr);
+ CHECK(class_linker->EnsureInitialized(self, h_ref_class, true, true));
+
+ Handle<mirror::Object> h_ref_instance(scope.NewHandle<mirror::Object>(
+ h_ref_class->AllocObject(self)));
+ CHECK(h_ref_instance.Get() != nullptr);
+
+ ArtMethod* constructor = h_ref_class->FindDeclaredDirectMethod(
+ "<init>", "(Ljava/lang/Object;)V", class_linker->GetImagePointerSize());
+ CHECK(constructor != nullptr);
+
+ uint32_t args[2];
+ args[0] = PointerToLowMemUInt32(h_ref_instance.Get());
+ args[1] = PointerToLowMemUInt32(h_referent.Get());
+ JValue result;
+ constructor->Invoke(self, args, sizeof(uint32_t), &result, constructor->GetShorty());
+ CHECK(!self->IsExceptionPending());
+
+ return h_ref_instance.Get();
+}
+
TEST_F(ReferenceTableTest, Basics) {
ScopedObjectAccess soa(Thread::Current());
mirror::Object* o1 = mirror::String::AllocFromModifiedUtf8(soa.Self(), "hello");
@@ -104,6 +141,29 @@
std::string::npos) << oss.str();
}
}
+
+ // Add a reference and check that the type of the referent is dumped.
+ {
+ mirror::Object* empty_reference = CreateWeakReference(nullptr);
+ ASSERT_TRUE(empty_reference->IsReferenceInstance());
+ rt.Add(empty_reference);
+ std::ostringstream oss;
+ rt.Dump(oss);
+ EXPECT_NE(oss.str().find("java.lang.ref.WeakReference (referent is null)"), std::string::npos)
+ << oss.str();
+ }
+
+ {
+ mirror::Object* string_referent = mirror::String::AllocFromModifiedUtf8(Thread::Current(), "A");
+ mirror::Object* non_empty_reference = CreateWeakReference(string_referent);
+ ASSERT_TRUE(non_empty_reference->IsReferenceInstance());
+ rt.Add(non_empty_reference);
+ std::ostringstream oss;
+ rt.Dump(oss);
+ EXPECT_NE(oss.str().find("java.lang.ref.WeakReference (referent is a java.lang.String)"),
+ std::string::npos)
+ << oss.str();
+ }
}
} // namespace art
diff --git a/runtime/thread_list.cc b/runtime/thread_list.cc
index 03b03de..17c6c2e 100644
--- a/runtime/thread_list.cc
+++ b/runtime/thread_list.cc
@@ -441,8 +441,8 @@
// runnable (both cases waiting inside Thread::TransitionFromSuspendedToRunnable), or waiting
// for the thread flip to end at the JNI critical section entry (kWaitingForGcThreadFlip),
ThreadState state = thread->GetState();
- if (state == kWaitingForGcThreadFlip ||
- thread->IsTransitioningToRunnable()) {
+ if ((state == kWaitingForGcThreadFlip || thread->IsTransitioningToRunnable()) &&
+ thread->GetSuspendCount() == 1) {
// The thread will resume right after the broadcast.
thread->ModifySuspendCount(self, -1, nullptr, false);
++runnable_thread_count;
diff --git a/runtime/well_known_classes.cc b/runtime/well_known_classes.cc
index 6b569f4..e5216fb 100644
--- a/runtime/well_known_classes.cc
+++ b/runtime/well_known_classes.cc
@@ -53,6 +53,8 @@
jclass WellKnownClasses::java_lang_reflect_Executable;
jclass WellKnownClasses::java_lang_reflect_Field;
jclass WellKnownClasses::java_lang_reflect_Method;
+jclass WellKnownClasses::java_lang_reflect_Parameter;
+jclass WellKnownClasses::java_lang_reflect_Parameter__array;
jclass WellKnownClasses::java_lang_reflect_Proxy;
jclass WellKnownClasses::java_lang_RuntimeException;
jclass WellKnownClasses::java_lang_StackOverflowError;
@@ -87,6 +89,7 @@
jmethodID WellKnownClasses::java_lang_Long_valueOf;
jmethodID WellKnownClasses::java_lang_ref_FinalizerReference_add;
jmethodID WellKnownClasses::java_lang_ref_ReferenceQueue_add;
+jmethodID WellKnownClasses::java_lang_reflect_Parameter_init;
jmethodID WellKnownClasses::java_lang_reflect_Proxy_invoke;
jmethodID WellKnownClasses::java_lang_Runtime_nativeLoad;
jmethodID WellKnownClasses::java_lang_Short_valueOf;
@@ -280,6 +283,8 @@
java_lang_reflect_Executable = CacheClass(env, "java/lang/reflect/Executable");
java_lang_reflect_Field = CacheClass(env, "java/lang/reflect/Field");
java_lang_reflect_Method = CacheClass(env, "java/lang/reflect/Method");
+ java_lang_reflect_Parameter = CacheClass(env, "java/lang/reflect/Parameter");
+ java_lang_reflect_Parameter__array = CacheClass(env, "[Ljava/lang/reflect/Parameter;");
java_lang_reflect_Proxy = CacheClass(env, "java/lang/reflect/Proxy");
java_lang_RuntimeException = CacheClass(env, "java/lang/RuntimeException");
java_lang_StackOverflowError = CacheClass(env, "java/lang/StackOverflowError");
@@ -312,6 +317,7 @@
ScopedLocalRef<jclass> java_lang_ref_ReferenceQueue(env, env->FindClass("java/lang/ref/ReferenceQueue"));
java_lang_ref_ReferenceQueue_add = CacheMethod(env, java_lang_ref_ReferenceQueue.get(), true, "add", "(Ljava/lang/ref/Reference;)V");
+ java_lang_reflect_Parameter_init = CacheMethod(env, java_lang_reflect_Parameter, false, "<init>", "(Ljava/lang/String;ILjava/lang/reflect/Executable;I)V");
java_lang_reflect_Proxy_invoke = CacheMethod(env, java_lang_reflect_Proxy, true, "invoke", "(Ljava/lang/reflect/Proxy;Ljava/lang/reflect/Method;[Ljava/lang/Object;)Ljava/lang/Object;");
java_lang_Thread_dispatchUncaughtException = CacheMethod(env, java_lang_Thread, false, "dispatchUncaughtException", "(Ljava/lang/Throwable;)V");
java_lang_Thread_init = CacheMethod(env, java_lang_Thread, false, "<init>", "(Ljava/lang/ThreadGroup;Ljava/lang/String;IZ)V");
diff --git a/runtime/well_known_classes.h b/runtime/well_known_classes.h
index c9110e6..ddfc5b8 100644
--- a/runtime/well_known_classes.h
+++ b/runtime/well_known_classes.h
@@ -67,6 +67,8 @@
static jclass java_lang_reflect_Executable;
static jclass java_lang_reflect_Field;
static jclass java_lang_reflect_Method;
+ static jclass java_lang_reflect_Parameter;
+ static jclass java_lang_reflect_Parameter__array;
static jclass java_lang_reflect_Proxy;
static jclass java_lang_RuntimeException;
static jclass java_lang_StackOverflowError;
@@ -101,6 +103,7 @@
static jmethodID java_lang_Long_valueOf;
static jmethodID java_lang_ref_FinalizerReference_add;
static jmethodID java_lang_ref_ReferenceQueue_add;
+ static jmethodID java_lang_reflect_Parameter_init;
static jmethodID java_lang_reflect_Proxy_invoke;
static jmethodID java_lang_Runtime_nativeLoad;
static jmethodID java_lang_Short_valueOf;
diff --git a/test/run-test b/test/run-test
index c50a9ca..7a4afaf 100755
--- a/test/run-test
+++ b/test/run-test
@@ -937,6 +937,7 @@
--raw-cmd="$raw_cmd" \
--check-script="$cwd/check" \
--expected-output="$cwd/expected.txt" \
+ --logfile="$cwd/bisection_log.txt" \
--timeout=300
fi
fi
diff --git a/tools/bisection_search/bisection_search.py b/tools/bisection_search/bisection_search.py
index c5971e6..27bd599 100755
--- a/tools/bisection_search/bisection_search.py
+++ b/tools/bisection_search/bisection_search.py
@@ -294,8 +294,7 @@
if faulty_method_idx == len(all_methods) + 1:
return (None, None)
if faulty_method_idx == 0:
- raise FatalError('Testable fails with no methods compiled. '
- 'Perhaps issue lies outside of compiler.')
+ raise FatalError('Testable fails with no methods compiled.')
faulty_method = all_methods[faulty_method_idx - 1]
all_passes = testable.GetAllPassesForMethod(faulty_method)
faulty_pass_idx = BinarySearch(
@@ -415,7 +414,11 @@
try:
testable = Dex2OatWrapperTestable(base_cmd, test_env, args.expected_retcode,
output_checker, args.verbose)
- (method, opt_pass) = BugSearch(testable)
+ if testable.Test(compiled_methods=[]):
+ (method, opt_pass) = BugSearch(testable)
+ else:
+ print('Testable fails with no methods compiled.')
+ sys.exit(1)
except Exception as e:
print('Error occurred.\nLogfile: {0}'.format(test_env.logfile.name))
test_env.logfile.write('Exception: {0}\n'.format(e))
diff --git a/tools/jfuzz/run_jfuzz_test_nightly.py b/tools/jfuzz/run_jfuzz_test_nightly.py
index cd338fb..29595f2 100755
--- a/tools/jfuzz/run_jfuzz_test_nightly.py
+++ b/tools/jfuzz/run_jfuzz_test_nightly.py
@@ -16,9 +16,14 @@
import argparse
import os
+import re
+import shutil
import subprocess
import sys
+from glob import glob
+
+from tempfile import mkdtemp
from tempfile import TemporaryFile
# Default arguments for run_jfuzz_test.py.
@@ -51,15 +56,29 @@
for proc in processes:
proc.kill()
# Output results.
+ output_dirs = []
for i, output_file in enumerate(output_files):
output_file.seek(0)
output_str = output_file.read().decode('ascii')
output_file.close()
+ # Extract output directory. Example match: 'Directory : /tmp/tmp8ltpfjng'.
+ directory_match = re.search(r'Directory[^:]*: ([^\n]+)\n', output_str)
+ if directory_match:
+ output_dirs.append(directory_match.group(1))
print('Tester', i)
if output_str.find(SUCCESS_STRING) == NOT_FOUND:
print(output_str)
else:
print(SUCCESS_STRING)
+ # Gather divergences.
+ global_out_dir = mkdtemp('jfuzz_nightly')
+ divergence_nr = 1
+ for out_dir in output_dirs:
+ for divergence_dir in glob(out_dir + '/divergence*/'):
+ shutil.copytree(divergence_dir,
+ global_out_dir + '/divergence' + str(divergence_nr))
+ divergence_nr += 1
+ print('Global output directory:', global_out_dir)
if __name__ == '__main__':
main(sys.argv)