summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Android.bp1
-rw-r--r--dex2oat/dex2oat_test.cc16
-rw-r--r--openjdkjvmti/OpenjdkJvmTi.cc3
-rw-r--r--openjdkjvmti/art_jvmti.h15
-rw-r--r--openjdkjvmti/events-inl.h5
-rw-r--r--openjdkjvmti/ti_breakpoint.cc8
-rw-r--r--openjdkjvmti/ti_field.cc4
-rw-r--r--openjdkjvmti/ti_field.h14
-rw-r--r--openjdkjvmti/ti_stack.cc9
-rw-r--r--runtime/class_linker.cc1
-rw-r--r--runtime/gc/collector/concurrent_copying.cc8
-rw-r--r--runtime/gc/heap.cc7
-rw-r--r--runtime/gc/heap.h4
-rwxr-xr-xtools/golem/build-target.sh12
14 files changed, 79 insertions, 28 deletions
diff --git a/Android.bp b/Android.bp
index 569179dc11..5e3a8d8bfa 100644
--- a/Android.bp
+++ b/Android.bp
@@ -12,6 +12,7 @@ art_static_dependencies = [
"libcutils",
"libunwindbacktrace",
"libunwind",
+ "libunwindstack",
"libutils",
"libbase",
"liblz4",
diff --git a/dex2oat/dex2oat_test.cc b/dex2oat/dex2oat_test.cc
index 1b731fc7f6..0e5776f39e 100644
--- a/dex2oat/dex2oat_test.cc
+++ b/dex2oat/dex2oat_test.cc
@@ -1372,9 +1372,19 @@ TEST_F(Dex2oatTest, LayoutSections) {
EXPECT_LT(code_item_offset - section_startup_only.offset_, section_startup_only.size_);
++startup_count;
} else {
- // If no flags are set, the method should be unused.
- EXPECT_LT(code_item_offset - section_unused.offset_, section_unused.size_);
- ++unused_count;
+ if (code_item_offset - section_unused.offset_ < section_unused.size_) {
+ // If no flags are set, the method should be unused ...
+ ++unused_count;
+ } else {
+ // or this method is part of the last code item and the end is 4 byte aligned.
+ ClassDataItemIterator it2(*dex_file, dex_file->GetClassData(*class_def));
+ it2.SkipAllFields();
+ for (; it2.HasNextDirectMethod() || it2.HasNextVirtualMethod(); it2.Next()) {
+ EXPECT_LE(it2.GetMethodCodeItemOffset(), code_item_offset);
+ }
+ uint32_t code_item_size = dex_file->FindCodeItemOffset(*class_def, method_idx);
+ EXPECT_EQ((code_item_offset + code_item_size) % 4, 0u);
+ }
}
}
DCHECK(!it.HasNext());
diff --git a/openjdkjvmti/OpenjdkJvmTi.cc b/openjdkjvmti/OpenjdkJvmTi.cc
index b30d45ae88..c2584e6944 100644
--- a/openjdkjvmti/OpenjdkJvmTi.cc
+++ b/openjdkjvmti/OpenjdkJvmTi.cc
@@ -1676,7 +1676,8 @@ extern const jvmtiInterface_1 gJvmtiInterface;
ArtJvmTiEnv::ArtJvmTiEnv(art::JavaVMExt* runtime, EventHandler* event_handler)
: art_vm(runtime),
local_data(nullptr),
- capabilities() {
+ capabilities(),
+ event_info_mutex_("jvmtiEnv_EventInfoMutex") {
object_tag_table = std::unique_ptr<ObjectTagTable>(new ObjectTagTable(event_handler, this));
functions = &gJvmtiInterface;
}
diff --git a/openjdkjvmti/art_jvmti.h b/openjdkjvmti/art_jvmti.h
index ad405e8571..3edefaf412 100644
--- a/openjdkjvmti/art_jvmti.h
+++ b/openjdkjvmti/art_jvmti.h
@@ -43,6 +43,7 @@
#include "base/logging.h"
#include "base/macros.h"
#include "base/strlcpy.h"
+#include "base/mutex.h"
#include "events.h"
#include "java_vm_ext.h"
#include "jni_env_ext.h"
@@ -59,6 +60,9 @@ namespace openjdkjvmti {
class ObjectTagTable;
+// Make sure that the DEFAULT_MUTEX_ACQUIRED_AFTER macro works.
+using art::Locks;
+
// A structure that is a jvmtiEnv with additional information for the runtime.
struct ArtJvmTiEnv : public jvmtiEnv {
art::JavaVMExt* art_vm;
@@ -77,12 +81,15 @@ struct ArtJvmTiEnv : public jvmtiEnv {
// or by putting a list in the ClassExt of a field's DeclaringClass.
// TODO Maybe just have an extension to let one put a watch on every field, that would probably be
// good enough maybe since you probably want either a few or all/almost all of them.
- std::unordered_set<art::ArtField*> access_watched_fields;
- std::unordered_set<art::ArtField*> modify_watched_fields;
+ std::unordered_set<art::ArtField*> access_watched_fields GUARDED_BY(event_info_mutex_);
+ std::unordered_set<art::ArtField*> modify_watched_fields GUARDED_BY(event_info_mutex_);
// Set of breakpoints is unique to each jvmtiEnv.
- std::unordered_set<Breakpoint> breakpoints;
- std::unordered_set<const art::ShadowFrame*> notify_frames;
+ std::unordered_set<Breakpoint> breakpoints GUARDED_BY(event_info_mutex_);
+ std::unordered_set<const art::ShadowFrame*> notify_frames GUARDED_BY(event_info_mutex_);
+
+ // RW lock to protect access to all of the event data.
+ art::ReaderWriterMutex event_info_mutex_ DEFAULT_MUTEX_ACQUIRED_AFTER;
ArtJvmTiEnv(art::JavaVMExt* runtime, EventHandler* event_handler);
diff --git a/openjdkjvmti/events-inl.h b/openjdkjvmti/events-inl.h
index ab8e6def2d..3973e9432f 100644
--- a/openjdkjvmti/events-inl.h
+++ b/openjdkjvmti/events-inl.h
@@ -21,6 +21,7 @@
#include <type_traits>
#include <tuple>
+#include "base/mutex-inl.h"
#include "events.h"
#include "jni_internal.h"
#include "nativehelper/ScopedLocalRef.h"
@@ -276,6 +277,7 @@ inline bool EventHandler::ShouldDispatch<ArtJvmtiEvent::kBreakpoint>(
jthread jni_thread ATTRIBUTE_UNUSED,
jmethodID jmethod,
jlocation location) const {
+ art::ReaderMutexLock lk(art::Thread::Current(), env->event_info_mutex_);
art::ArtMethod* method = art::jni::DecodeArtMethod(jmethod);
return ShouldDispatchOnThread<ArtJvmtiEvent::kBreakpoint>(env, thread) &&
env->breakpoints.find({method, location}) != env->breakpoints.end();
@@ -292,6 +294,7 @@ inline bool EventHandler::ShouldDispatch<ArtJvmtiEvent::kFramePop>(
const art::ShadowFrame* frame) const {
// Search for the frame. Do this before checking if we need to send the event so that we don't
// have to deal with use-after-free or the frames being reallocated later.
+ art::WriterMutexLock lk(art::Thread::Current(), env->event_info_mutex_);
return env->notify_frames.erase(frame) != 0 &&
ShouldDispatchOnThread<ArtJvmtiEvent::kFramePop>(env, thread);
}
@@ -313,6 +316,7 @@ inline bool EventHandler::ShouldDispatch<ArtJvmtiEvent::kFieldModification>(
jfieldID field,
char type_char ATTRIBUTE_UNUSED,
jvalue val ATTRIBUTE_UNUSED) const {
+ art::ReaderMutexLock lk(art::Thread::Current(), env->event_info_mutex_);
return ShouldDispatchOnThread<ArtJvmtiEvent::kFieldModification>(env, thread) &&
env->modify_watched_fields.find(
art::jni::DecodeArtField(field)) != env->modify_watched_fields.end();
@@ -329,6 +333,7 @@ inline bool EventHandler::ShouldDispatch<ArtJvmtiEvent::kFieldAccess>(
jclass field_klass ATTRIBUTE_UNUSED,
jobject object ATTRIBUTE_UNUSED,
jfieldID field) const {
+ art::ReaderMutexLock lk(art::Thread::Current(), env->event_info_mutex_);
return ShouldDispatchOnThread<ArtJvmtiEvent::kFieldAccess>(env, thread) &&
env->access_watched_fields.find(
art::jni::DecodeArtField(field)) != env->access_watched_fields.end();
diff --git a/openjdkjvmti/ti_breakpoint.cc b/openjdkjvmti/ti_breakpoint.cc
index f5116a8080..75c8027b22 100644
--- a/openjdkjvmti/ti_breakpoint.cc
+++ b/openjdkjvmti/ti_breakpoint.cc
@@ -36,6 +36,7 @@
#include "art_jvmti.h"
#include "art_method-inl.h"
#include "base/enums.h"
+#include "base/mutex-inl.h"
#include "dex_file_annotations.h"
#include "events-inl.h"
#include "jni_internal.h"
@@ -62,6 +63,7 @@ Breakpoint::Breakpoint(art::ArtMethod* m, jlocation loc) : method_(m), location_
}
void BreakpointUtil::RemoveBreakpointsInClass(ArtJvmTiEnv* env, art::mirror::Class* klass) {
+ art::WriterMutexLock lk(art::Thread::Current(), env->event_info_mutex_);
std::vector<Breakpoint> to_remove;
for (const Breakpoint& b : env->breakpoints) {
if (b.GetMethod()->GetDeclaringClass() == klass) {
@@ -83,6 +85,7 @@ jvmtiError BreakpointUtil::SetBreakpoint(jvmtiEnv* jenv, jmethodID method, jloca
// Need to get mutator_lock_ so we can find the interface version of any default methods.
art::ScopedObjectAccess soa(art::Thread::Current());
art::ArtMethod* art_method = art::jni::DecodeArtMethod(method)->GetCanonicalMethod();
+ art::WriterMutexLock lk(art::Thread::Current(), env->event_info_mutex_);
if (location < 0 || static_cast<uint32_t>(location) >=
art_method->GetCodeItem()->insns_size_in_code_units_) {
return ERR(INVALID_LOCATION);
@@ -102,8 +105,9 @@ jvmtiError BreakpointUtil::ClearBreakpoint(jvmtiEnv* jenv, jmethodID method, jlo
}
// Need to get mutator_lock_ so we can find the interface version of any default methods.
art::ScopedObjectAccess soa(art::Thread::Current());
- auto pos = env->breakpoints.find(
- /* Breakpoint */ {art::jni::DecodeArtMethod(method)->GetCanonicalMethod(), location});
+ art::ArtMethod* art_method = art::jni::DecodeArtMethod(method)->GetCanonicalMethod();
+ art::WriterMutexLock lk(art::Thread::Current(), env->event_info_mutex_);
+ auto pos = env->breakpoints.find(/* Breakpoint */ {art_method, location});
if (pos == env->breakpoints.end()) {
return ERR(NOT_FOUND);
}
diff --git a/openjdkjvmti/ti_field.cc b/openjdkjvmti/ti_field.cc
index c45b926695..b8691837eb 100644
--- a/openjdkjvmti/ti_field.cc
+++ b/openjdkjvmti/ti_field.cc
@@ -189,6 +189,7 @@ jvmtiError FieldUtil::IsFieldSynthetic(jvmtiEnv* env ATTRIBUTE_UNUSED,
jvmtiError FieldUtil::SetFieldModificationWatch(jvmtiEnv* jenv, jclass klass, jfieldID field) {
ArtJvmTiEnv* env = ArtJvmTiEnv::AsArtJvmTiEnv(jenv);
+ art::WriterMutexLock lk(art::Thread::Current(), env->event_info_mutex_);
if (klass == nullptr) {
return ERR(INVALID_CLASS);
}
@@ -205,6 +206,7 @@ jvmtiError FieldUtil::SetFieldModificationWatch(jvmtiEnv* jenv, jclass klass, jf
jvmtiError FieldUtil::ClearFieldModificationWatch(jvmtiEnv* jenv, jclass klass, jfieldID field) {
ArtJvmTiEnv* env = ArtJvmTiEnv::AsArtJvmTiEnv(jenv);
+ art::WriterMutexLock lk(art::Thread::Current(), env->event_info_mutex_);
if (klass == nullptr) {
return ERR(INVALID_CLASS);
}
@@ -221,6 +223,7 @@ jvmtiError FieldUtil::ClearFieldModificationWatch(jvmtiEnv* jenv, jclass klass,
jvmtiError FieldUtil::SetFieldAccessWatch(jvmtiEnv* jenv, jclass klass, jfieldID field) {
ArtJvmTiEnv* env = ArtJvmTiEnv::AsArtJvmTiEnv(jenv);
+ art::WriterMutexLock lk(art::Thread::Current(), env->event_info_mutex_);
if (klass == nullptr) {
return ERR(INVALID_CLASS);
}
@@ -237,6 +240,7 @@ jvmtiError FieldUtil::SetFieldAccessWatch(jvmtiEnv* jenv, jclass klass, jfieldID
jvmtiError FieldUtil::ClearFieldAccessWatch(jvmtiEnv* jenv, jclass klass, jfieldID field) {
ArtJvmTiEnv* env = ArtJvmTiEnv::AsArtJvmTiEnv(jenv);
+ art::WriterMutexLock lk(art::Thread::Current(), env->event_info_mutex_);
if (klass == nullptr) {
return ERR(INVALID_CLASS);
}
diff --git a/openjdkjvmti/ti_field.h b/openjdkjvmti/ti_field.h
index 8a229ed19d..3cf29f099a 100644
--- a/openjdkjvmti/ti_field.h
+++ b/openjdkjvmti/ti_field.h
@@ -35,6 +35,8 @@
#include "jni.h"
#include "jvmti.h"
+#include "art_jvmti.h"
+
namespace openjdkjvmti {
class FieldUtil {
@@ -61,10 +63,14 @@ class FieldUtil {
jfieldID field,
jboolean* is_synthetic_ptr);
- static jvmtiError SetFieldModificationWatch(jvmtiEnv* env, jclass klass, jfieldID field);
- static jvmtiError ClearFieldModificationWatch(jvmtiEnv* env, jclass klass, jfieldID field);
- static jvmtiError SetFieldAccessWatch(jvmtiEnv* env, jclass klass, jfieldID field);
- static jvmtiError ClearFieldAccessWatch(jvmtiEnv* env, jclass klass, jfieldID field);
+ static jvmtiError SetFieldModificationWatch(jvmtiEnv* env, jclass klass, jfieldID field)
+ REQUIRES(!ArtJvmTiEnv::event_info_mutex_);
+ static jvmtiError ClearFieldModificationWatch(jvmtiEnv* env, jclass klass, jfieldID field)
+ REQUIRES(!ArtJvmTiEnv::event_info_mutex_);
+ static jvmtiError SetFieldAccessWatch(jvmtiEnv* env, jclass klass, jfieldID field)
+ REQUIRES(!ArtJvmTiEnv::event_info_mutex_);
+ static jvmtiError ClearFieldAccessWatch(jvmtiEnv* env, jclass klass, jfieldID field)
+ REQUIRES(!ArtJvmTiEnv::event_info_mutex_);
};
} // namespace openjdkjvmti
diff --git a/openjdkjvmti/ti_stack.cc b/openjdkjvmti/ti_stack.cc
index e0c139954d..23cf659c67 100644
--- a/openjdkjvmti/ti_stack.cc
+++ b/openjdkjvmti/ti_stack.cc
@@ -1024,9 +1024,12 @@ jvmtiError StackUtil::NotifyFramePop(jvmtiEnv* env, jthread thread, jint depth)
method,
visitor.GetDexPc());
}
- // Mark shadow frame as needs_notify_pop_
- shadow_frame->SetNotifyPop(true);
- tienv->notify_frames.insert(shadow_frame);
+ {
+ art::WriterMutexLock lk(self, tienv->event_info_mutex_);
+ // Mark shadow frame as needs_notify_pop_
+ shadow_frame->SetNotifyPop(true);
+ tienv->notify_frames.insert(shadow_frame);
+ }
// Make sure can we will go to the interpreter and use the shadow frames.
if (needs_instrument) {
art::Runtime::Current()->GetInstrumentation()->InstrumentThreadStack(target);
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index d3eb29ba0b..cd7a94e3d1 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -1819,6 +1819,7 @@ bool ClassLinker::AddImageSpace(
if (kIsDebugBuild && app_image) {
// This verification needs to happen after the classes have been added to the class loader.
// Since it ensures classes are in the class table.
+ ScopedTrace trace("VerifyAppImage");
VerifyAppImage(header, class_loader, dex_caches, class_table, space);
}
diff --git a/runtime/gc/collector/concurrent_copying.cc b/runtime/gc/collector/concurrent_copying.cc
index 52b355dedd..4d4d8ffb58 100644
--- a/runtime/gc/collector/concurrent_copying.cc
+++ b/runtime/gc/collector/concurrent_copying.cc
@@ -2153,14 +2153,18 @@ void ConcurrentCopying::FillWithDummyObject(mirror::Object* dummy_obj, size_t by
mirror::Class* int_array_class = down_cast<mirror::Class*>(
Mark(mirror::IntArray::GetArrayClass<kWithoutReadBarrier>()));
CHECK(int_array_class != nullptr);
- AssertToSpaceInvariant(nullptr, MemberOffset(0), int_array_class);
+ if (ReadBarrier::kEnableToSpaceInvariantChecks) {
+ AssertToSpaceInvariant(nullptr, MemberOffset(0), int_array_class);
+ }
size_t component_size = int_array_class->GetComponentSize<kWithoutReadBarrier>();
CHECK_EQ(component_size, sizeof(int32_t));
size_t data_offset = mirror::Array::DataOffset(component_size).SizeValue();
if (data_offset > byte_size) {
// An int array is too big. Use java.lang.Object.
CHECK(java_lang_Object_ != nullptr);
- AssertToSpaceInvariant(nullptr, MemberOffset(0), java_lang_Object_);
+ if (ReadBarrier::kEnableToSpaceInvariantChecks) {
+ AssertToSpaceInvariant(nullptr, MemberOffset(0), java_lang_Object_);
+ }
CHECK_EQ(byte_size, (java_lang_Object_->GetObjectSize<kVerifyNone, kWithoutReadBarrier>()));
dummy_obj->SetClass(java_lang_Object_);
CHECK_EQ(byte_size, (dummy_obj->SizeOf<kVerifyNone>()));
diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc
index 67e8a0d02f..7328063486 100644
--- a/runtime/gc/heap.cc
+++ b/runtime/gc/heap.cc
@@ -93,6 +93,9 @@ namespace gc {
static constexpr size_t kCollectorTransitionStressIterations = 0;
static constexpr size_t kCollectorTransitionStressWait = 10 * 1000; // Microseconds
+
+DEFINE_RUNTIME_DEBUG_FLAG(Heap, kStressCollectorTransition);
+
// Minimum amount of remaining bytes before a concurrent GC is triggered.
static constexpr size_t kMinConcurrentRemainingBytes = 128 * KB;
static constexpr size_t kMaxConcurrentRemainingBytes = 512 * KB;
@@ -889,7 +892,9 @@ void Heap::UpdateProcessState(ProcessState old_process_state, ProcessState new_p
// the collector. Similarly, we invoke a full compaction for kCollectorTypeCC but don't
// transition the collector.
RequestCollectorTransition(background_collector_type_,
- kIsDebugBuild ? 0 : kCollectorTransitionWait);
+ kStressCollectorTransition
+ ? 0
+ : kCollectorTransitionWait);
}
}
}
diff --git a/runtime/gc/heap.h b/runtime/gc/heap.h
index d673b4ac29..7b4fab607f 100644
--- a/runtime/gc/heap.h
+++ b/runtime/gc/heap.h
@@ -25,6 +25,7 @@
#include "allocator_type.h"
#include "arch/instruction_set.h"
#include "atomic.h"
+#include "base/logging.h"
#include "base/mutex.h"
#include "base/time_utils.h"
#include "gc/collector/gc_type.h"
@@ -155,6 +156,9 @@ class Heap {
static constexpr uint64_t kHeapTrimWait = MsToNs(5000);
// How long we wait after a transition request to perform a collector transition (nanoseconds).
static constexpr uint64_t kCollectorTransitionWait = MsToNs(5000);
+ // Whether the transition-wait applies or not. Zero wait will stress the
+ // transition code and collector, but increases jank probability.
+ DECLARE_RUNTIME_DEBUG_FLAG(kStressCollectorTransition);
// Create a heap with the requested sizes. The possible empty
// image_file_names names specify Spaces to load based on
diff --git a/tools/golem/build-target.sh b/tools/golem/build-target.sh
index 8d8e2bbe6f..4ca2722ac9 100755
--- a/tools/golem/build-target.sh
+++ b/tools/golem/build-target.sh
@@ -147,12 +147,8 @@ get_build_var() {
[[ -n $target_product ]] && extras+=" TARGET_PRODUCT=$target_product"
[[ -n $target_build_variant ]] && extras+=" TARGET_BUILD_VARIANT=$target_build_variant"
- # call dumpvar-$name from the makefile system.
- (\cd "$(gettop)";
- CALLED_FROM_SETUP=true BUILD_SYSTEM=build/core \
- command make --no-print-directory -f build/core/config.mk \
- $extras \
- dumpvar-$varname)
+ # call dumpvar from the build system.
+ (\cd "$(gettop)"; env $extras build/soong/soong_ui.bash --dumpvar-mode $varname)
}
# Defaults from command-line.
@@ -160,7 +156,7 @@ get_build_var() {
mode="" # blank or 'golem' if --golem was specified.
golem_target="" # --golem=$golem_target
config="" # --machine-type=$config
-j_arg="-j8"
+j_arg=""
showcommands=""
simulate=""
make_tarball=""
@@ -353,7 +349,7 @@ fi
# and maybe calls lunch).
#
-execute make "${j_arg}" "${make_target}"
+execute build/soong/soong_ui.bash --make-mode "${j_arg}" "${make_target}"
if $strip_symbols; then
# Further reduce size by stripping symbols.