Merge "ART: Add DataDumpRequest"
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index faf8b41..c03ffca 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -284,7 +284,7 @@
verification_results_(verification_results),
compiler_(Compiler::Create(this, compiler_kind)),
compiler_kind_(compiler_kind),
- instruction_set_(instruction_set == kArm ? kThumb2: instruction_set),
+ instruction_set_(instruction_set == kArm ? kThumb2 : instruction_set),
instruction_set_features_(instruction_set_features),
requires_constructor_barrier_lock_("constructor barrier lock"),
compiled_classes_lock_("compiled classes lock"),
@@ -1251,7 +1251,7 @@
}
}
- // java.lang.Reference visitor for VisitReferences.
+ // java.lang.ref.Reference visitor for VisitReferences.
void operator()(ObjPtr<mirror::Class> klass ATTRIBUTE_UNUSED,
ObjPtr<mirror::Reference> ref ATTRIBUTE_UNUSED) const {}
diff --git a/compiler/jni/quick/x86_64/calling_convention_x86_64.cc b/compiler/jni/quick/x86_64/calling_convention_x86_64.cc
index 8ca0ffe..ba654f4 100644
--- a/compiler/jni/quick/x86_64/calling_convention_x86_64.cc
+++ b/compiler/jni/quick/x86_64/calling_convention_x86_64.cc
@@ -160,7 +160,7 @@
while (HasNext()) {
ManagedRegister in_reg = CurrentParamRegister();
if (!in_reg.IsNoRegister()) {
- int32_t size = IsParamALongOrDouble(itr_args_)? 8 : 4;
+ int32_t size = IsParamALongOrDouble(itr_args_) ? 8 : 4;
int32_t spill_offset = CurrentParamStackOffset().Uint32Value();
ManagedRegisterSpill spill(in_reg, size, spill_offset);
entry_spills_.push_back(spill);
diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc
index 2a30178..f5b6ebe 100644
--- a/compiler/optimizing/code_generator_arm.cc
+++ b/compiler/optimizing/code_generator_arm.cc
@@ -3332,7 +3332,7 @@
InvokeRuntimeCallingConvention calling_convention;
locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
- // Note: divrem will compute both the quotient and the remainder as the pair R0 and R1, but
+ // Note: divmod will compute both the quotient and the remainder as the pair R0 and R1, but
// we only need the former.
locations->SetOut(Location::RegisterLocation(R0));
}
@@ -3459,7 +3459,7 @@
InvokeRuntimeCallingConvention calling_convention;
locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
- // Note: divrem will compute both the quotient and the remainder as the pair R0 and R1, but
+ // Note: divmod will compute both the quotient and the remainder as the pair R0 and R1, but
// we only need the latter.
locations->SetOut(Location::RegisterLocation(R1));
}
diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc
index d4dcbc0..9762ee8 100644
--- a/compiler/optimizing/code_generator_arm64.cc
+++ b/compiler/optimizing/code_generator_arm64.cc
@@ -4662,7 +4662,7 @@
}
void InstructionCodeGeneratorARM64::VisitMonitorOperation(HMonitorOperation* instruction) {
- codegen_->InvokeRuntime(instruction->IsEnter() ? kQuickLockObject: kQuickUnlockObject,
+ codegen_->InvokeRuntime(instruction->IsEnter() ? kQuickLockObject : kQuickUnlockObject,
instruction,
instruction->GetDexPc());
if (instruction->IsEnter()) {
diff --git a/compiler/optimizing/code_generator_arm_vixl.cc b/compiler/optimizing/code_generator_arm_vixl.cc
index 6c66f8f..ffaf18f 100644
--- a/compiler/optimizing/code_generator_arm_vixl.cc
+++ b/compiler/optimizing/code_generator_arm_vixl.cc
@@ -3336,7 +3336,7 @@
InvokeRuntimeCallingConventionARMVIXL calling_convention;
locations->SetInAt(0, LocationFrom(calling_convention.GetRegisterAt(0)));
locations->SetInAt(1, LocationFrom(calling_convention.GetRegisterAt(1)));
- // Note: divrem will compute both the quotient and the remainder as the pair R0 and R1, but
+ // Note: divmod will compute both the quotient and the remainder as the pair R0 and R1, but
// we only need the former.
locations->SetOut(LocationFrom(r0));
}
@@ -3450,7 +3450,7 @@
InvokeRuntimeCallingConventionARMVIXL calling_convention;
locations->SetInAt(0, LocationFrom(calling_convention.GetRegisterAt(0)));
locations->SetInAt(1, LocationFrom(calling_convention.GetRegisterAt(1)));
- // Note: divrem will compute both the quotient and the remainder as the pair R0 and R1, but
+ // Note: divmod will compute both the quotient and the remainder as the pair R0 and R1, but
// we only need the latter.
locations->SetOut(LocationFrom(r1));
}
diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc
index 853c91f..5c561f5 100644
--- a/compiler/optimizing/code_generator_x86.cc
+++ b/compiler/optimizing/code_generator_x86.cc
@@ -1778,7 +1778,7 @@
cond = X86Condition(condition->GetCondition());
}
} else {
- // Must be a boolean condition, which needs to be compared to 0.
+ // Must be a Boolean condition, which needs to be compared to 0.
Register cond_reg = locations->InAt(2).AsRegister<Register>();
__ testl(cond_reg, cond_reg);
}
diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc
index 74c71cc..c4caf4b 100644
--- a/compiler/optimizing/code_generator_x86_64.cc
+++ b/compiler/optimizing/code_generator_x86_64.cc
@@ -1809,7 +1809,7 @@
cond = X86_64IntegerCondition(condition->GetCondition());
}
} else {
- // Must be a boolean condition, which needs to be compared to 0.
+ // Must be a Boolean condition, which needs to be compared to 0.
CpuRegister cond_reg = locations->InAt(2).AsRegister<CpuRegister>();
__ testl(cond_reg, cond_reg);
}
@@ -4210,7 +4210,7 @@
void CodeGeneratorX86_64::GenerateMemoryBarrier(MemBarrierKind kind) {
/*
- * According to the JSR-133 Cookbook, for x86 only StoreLoad/AnyAny barriers need memory fence.
+ * According to the JSR-133 Cookbook, for x86-64 only StoreLoad/AnyAny barriers need memory fence.
* All other barriers (LoadAny, AnyStore, StoreStore) are nops due to the x86-64 memory model.
* For those cases, all we need to ensure is that there is a scheduling barrier in place.
*/
diff --git a/compiler/optimizing/gvn.cc b/compiler/optimizing/gvn.cc
index f5931a2..c93bc21 100644
--- a/compiler/optimizing/gvn.cc
+++ b/compiler/optimizing/gvn.cc
@@ -399,7 +399,7 @@
ArenaVector<ValueSet*> sets_;
// BitVector which serves as a fast-access map from block id to
- // visited/unvisited boolean.
+ // visited/unvisited Boolean.
ArenaBitVector visited_blocks_;
DISALLOW_COPY_AND_ASSIGN(GlobalValueNumberer);
diff --git a/compiler/optimizing/instruction_builder.cc b/compiler/optimizing/instruction_builder.cc
index ef8d74d..cac385c 100644
--- a/compiler/optimizing/instruction_builder.cc
+++ b/compiler/optimizing/instruction_builder.cc
@@ -1,4 +1,3 @@
-
/*
* Copyright (C) 2016 The Android Open Source Project
*
diff --git a/compiler/optimizing/intrinsics_mips.cc b/compiler/optimizing/intrinsics_mips.cc
index f1ae549..6cf9b83 100644
--- a/compiler/optimizing/intrinsics_mips.cc
+++ b/compiler/optimizing/intrinsics_mips.cc
@@ -1878,7 +1878,7 @@
// If we use 'value' directly, we would lose 'value'
// in the case that the store fails. Whether the
// store succeeds, or fails, it will load the
- // correct boolean value into the 'out' register.
+ // correct Boolean value into the 'out' register.
// This test isn't really necessary. We only support Primitive::kPrimInt,
// Primitive::kPrimNot, and we already verified that we're working on one
// of those two types. It's left here in case the code needs to support
diff --git a/compiler/optimizing/intrinsics_mips64.cc b/compiler/optimizing/intrinsics_mips64.cc
index 3022e97..00a1fa1 100644
--- a/compiler/optimizing/intrinsics_mips64.cc
+++ b/compiler/optimizing/intrinsics_mips64.cc
@@ -1477,7 +1477,7 @@
// If we use 'value' directly, we would lose 'value'
// in the case that the store fails. Whether the
// store succeeds, or fails, it will load the
- // correct boolean value into the 'out' register.
+ // correct Boolean value into the 'out' register.
if (type == Primitive::kPrimLong) {
__ Scd(out, TMP);
} else {
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index a2980dc..f0ea9e2 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -565,7 +565,7 @@
ArtMethod* GetArtMethod() const { return art_method_; }
void SetArtMethod(ArtMethod* method) { art_method_ = method; }
- // Returns an instruction with the opposite boolean value from 'cond'.
+ // Returns an instruction with the opposite Boolean value from 'cond'.
// The instruction has been inserted into the graph, either as a constant, or
// before cursor.
HInstruction* InsertOppositeCondition(HInstruction* cond, HInstruction* cursor);
diff --git a/dexlayout/dex_ir.h b/dexlayout/dex_ir.h
index a2d1190..e2ee940 100644
--- a/dexlayout/dex_ir.h
+++ b/dexlayout/dex_ir.h
@@ -741,7 +741,7 @@
uint32_t GetAccessFlags() const { return access_flags_; }
const TypeId* Superclass() const { return superclass_; }
const TypeIdVector* Interfaces()
- { return interfaces_ == nullptr ? nullptr: interfaces_->GetTypeList(); }
+ { return interfaces_ == nullptr ? nullptr : interfaces_->GetTypeList(); }
uint32_t InterfacesOffset() { return interfaces_ == nullptr ? 0 : interfaces_->GetOffset(); }
const StringId* SourceFile() const { return source_file_; }
AnnotationsDirectoryItem* Annotations() const { return annotations_; }
diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc
index 3cf900e..92f1e18 100644
--- a/oatdump/oatdump.cc
+++ b/oatdump/oatdump.cc
@@ -1784,7 +1784,7 @@
os << StringPrintf("%d (0x%x)\n", field->GetShort(obj), field->GetShort(obj));
break;
case Primitive::kPrimBoolean:
- os << StringPrintf("%s (0x%x)\n", field->GetBoolean(obj)? "true" : "false",
+ os << StringPrintf("%s (0x%x)\n", field->GetBoolean(obj) ? "true" : "false",
field->GetBoolean(obj));
break;
case Primitive::kPrimByte:
diff --git a/runtime/arch/arm/quick_method_frame_info_arm.h b/runtime/arch/arm/quick_method_frame_info_arm.h
index 4b23c77..35f1948 100644
--- a/runtime/arch/arm/quick_method_frame_info_arm.h
+++ b/runtime/arch/arm/quick_method_frame_info_arm.h
@@ -62,7 +62,7 @@
constexpr uint32_t ArmCalleeSaveFpSpills(Runtime::CalleeSaveType type) {
return kArmCalleeSaveFpAlwaysSpills | kArmCalleeSaveFpRefSpills |
- (type == Runtime::kSaveRefsAndArgs ? kArmCalleeSaveFpArgSpills: 0) |
+ (type == Runtime::kSaveRefsAndArgs ? kArmCalleeSaveFpArgSpills : 0) |
(type == Runtime::kSaveAllCalleeSaves ? kArmCalleeSaveFpAllSpills : 0) |
(type == Runtime::kSaveEverything ? kArmCalleeSaveFpEverythingSpills : 0);
}
diff --git a/runtime/arch/arm64/quick_method_frame_info_arm64.h b/runtime/arch/arm64/quick_method_frame_info_arm64.h
index 36f283b..32d9d08 100644
--- a/runtime/arch/arm64/quick_method_frame_info_arm64.h
+++ b/runtime/arch/arm64/quick_method_frame_info_arm64.h
@@ -85,7 +85,7 @@
constexpr uint32_t Arm64CalleeSaveFpSpills(Runtime::CalleeSaveType type) {
return kArm64CalleeSaveFpAlwaysSpills | kArm64CalleeSaveFpRefSpills |
- (type == Runtime::kSaveRefsAndArgs ? kArm64CalleeSaveFpArgSpills: 0) |
+ (type == Runtime::kSaveRefsAndArgs ? kArm64CalleeSaveFpArgSpills : 0) |
(type == Runtime::kSaveAllCalleeSaves ? kArm64CalleeSaveFpAllSpills : 0) |
(type == Runtime::kSaveEverything ? kArm64CalleeSaveFpEverythingSpills : 0);
}
diff --git a/runtime/arch/mips64/quick_method_frame_info_mips64.h b/runtime/arch/mips64/quick_method_frame_info_mips64.h
index 397776e..d774473 100644
--- a/runtime/arch/mips64/quick_method_frame_info_mips64.h
+++ b/runtime/arch/mips64/quick_method_frame_info_mips64.h
@@ -78,7 +78,7 @@
constexpr uint32_t Mips64CalleeSaveFpSpills(Runtime::CalleeSaveType type) {
return kMips64CalleeSaveFpRefSpills |
- (type == Runtime::kSaveRefsAndArgs ? kMips64CalleeSaveFpArgSpills: 0) |
+ (type == Runtime::kSaveRefsAndArgs ? kMips64CalleeSaveFpArgSpills : 0) |
(type == Runtime::kSaveAllCalleeSaves ? kMips64CalleeSaveFpAllSpills : 0) |
(type == Runtime::kSaveEverything ? kMips64CalleeSaveFpEverythingSpills : 0);
}
diff --git a/runtime/class_linker_test.cc b/runtime/class_linker_test.cc
index 7d4b158..7b6c0dc 100644
--- a/runtime/class_linker_test.cc
+++ b/runtime/class_linker_test.cc
@@ -487,7 +487,7 @@
// says AccessibleObject is 9 bytes but sizeof(AccessibleObject) is 12 bytes due to padding.
// The RoundUp is to get around this case.
static constexpr size_t kPackAlignment = 4;
- size_t expected_size = RoundUp(is_static ? klass->GetClassSize(): klass->GetObjectSize(),
+ size_t expected_size = RoundUp(is_static ? klass->GetClassSize() : klass->GetObjectSize(),
kPackAlignment);
if (sizeof(T) != expected_size) {
LOG(ERROR) << "Class size mismatch:"
diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc
index 34d8284..268cca0 100644
--- a/runtime/gc/heap.cc
+++ b/runtime/gc/heap.cc
@@ -360,7 +360,7 @@
// If we are the zygote, the non moving space becomes the zygote space when we run
// PreZygoteFork the first time. In this case, call the map "zygote space" since we can't
// rename the mem map later.
- const char* space_name = is_zygote ? kZygoteSpaceName: kNonMovingSpaceName;
+ const char* space_name = is_zygote ? kZygoteSpaceName : kNonMovingSpaceName;
// Reserve the non moving mem map before the other two since it needs to be at a specific
// address.
non_moving_space_mem_map.reset(
diff --git a/runtime/gc/reference_processor.h b/runtime/gc/reference_processor.h
index b15544d..38b68cb 100644
--- a/runtime/gc/reference_processor.h
+++ b/runtime/gc/reference_processor.h
@@ -42,7 +42,7 @@
class Heap;
-// Used to process java.lang.References concurrently or paused.
+// Used to process java.lang.ref.Reference instances concurrently or paused.
class ReferenceProcessor {
public:
explicit ReferenceProcessor();
diff --git a/runtime/gc/scoped_gc_critical_section.h b/runtime/gc/scoped_gc_critical_section.h
index ec93bca..1271ff7 100644
--- a/runtime/gc/scoped_gc_critical_section.h
+++ b/runtime/gc/scoped_gc_critical_section.h
@@ -27,8 +27,8 @@
namespace gc {
-// Wait until the GC is finished and then prevent GC from starting until the destructor. Used
-// to prevent deadlocks in places where we call ClassLinker::VisitClass with all th threads
+// Wait until the GC is finished and then prevent the GC from starting until the destructor. Used
+// to prevent deadlocks in places where we call ClassLinker::VisitClass with all the threads
// suspended.
class ScopedGCCriticalSection {
public:
diff --git a/runtime/interpreter/mterp/arm64/op_iput_wide_quick.S b/runtime/interpreter/mterp/arm64/op_iput_wide_quick.S
index 6cec363..28e831a 100644
--- a/runtime/interpreter/mterp/arm64/op_iput_wide_quick.S
+++ b/runtime/interpreter/mterp/arm64/op_iput_wide_quick.S
@@ -4,7 +4,7 @@
GET_VREG w2, w2 // w2<- fp[B], the object pointer
ubfx w0, wINST, #8, #4 // w0<- A
cbz w2, common_errNullObject // object was null
- GET_VREG_WIDE x0, w0 // x0-< fp[A]
+ GET_VREG_WIDE x0, w0 // x0<- fp[A]
FETCH_ADVANCE_INST 2 // advance rPC, load wINST
str x0, [x2, x3] // obj.field<- x0
GET_INST_OPCODE ip // extract opcode from wINST
diff --git a/runtime/interpreter/mterp/out/mterp_arm64.S b/runtime/interpreter/mterp/out/mterp_arm64.S
index 681790d..7d442c0 100644
--- a/runtime/interpreter/mterp/out/mterp_arm64.S
+++ b/runtime/interpreter/mterp/out/mterp_arm64.S
@@ -6593,7 +6593,7 @@
GET_VREG w2, w2 // w2<- fp[B], the object pointer
ubfx w0, wINST, #8, #4 // w0<- A
cbz w2, common_errNullObject // object was null
- GET_VREG_WIDE x0, w0 // x0-< fp[A]
+ GET_VREG_WIDE x0, w0 // x0<- fp[A]
FETCH_ADVANCE_INST 2 // advance rPC, load wINST
str x0, [x2, x3] // obj.field<- x0
GET_INST_OPCODE ip // extract opcode from wINST
diff --git a/runtime/interpreter/unstarted_runtime.cc b/runtime/interpreter/unstarted_runtime.cc
index 7dd3d3d..feb6e08 100644
--- a/runtime/interpreter/unstarted_runtime.cc
+++ b/runtime/interpreter/unstarted_runtime.cc
@@ -1443,7 +1443,7 @@
ObjPtr<mirror::Object> java_method_obj = shadow_frame->GetVRegReference(arg_offset);
ScopedLocalRef<jobject> java_method(env,
- java_method_obj == nullptr ? nullptr :env->AddLocalReference<jobject>(java_method_obj));
+ java_method_obj == nullptr ? nullptr : env->AddLocalReference<jobject>(java_method_obj));
ObjPtr<mirror::Object> java_receiver_obj = shadow_frame->GetVRegReference(arg_offset + 1);
ScopedLocalRef<jobject> java_receiver(env,
diff --git a/runtime/monitor.cc b/runtime/monitor.cc
index 9c09275..071b0e2 100644
--- a/runtime/monitor.cc
+++ b/runtime/monitor.cc
@@ -1394,6 +1394,12 @@
}
}
+size_t MonitorList::Size() {
+ Thread* self = Thread::Current();
+ MutexLock mu(self, monitor_list_lock_);
+ return list_.size();
+}
+
class MonitorDeflateVisitor : public IsMarkedVisitor {
public:
MonitorDeflateVisitor() : self_(Thread::Current()), deflate_count_(0) {}
diff --git a/runtime/monitor.h b/runtime/monitor.h
index c3da563..1fa4682 100644
--- a/runtime/monitor.h
+++ b/runtime/monitor.h
@@ -331,6 +331,7 @@
void BroadcastForNewMonitors() REQUIRES(!monitor_list_lock_);
// Returns how many monitors were deflated.
size_t DeflateMonitors() REQUIRES(!monitor_list_lock_) REQUIRES(Locks::mutator_lock_);
+ size_t Size() REQUIRES(!monitor_list_lock_);
typedef std::list<Monitor*, TrackingAllocator<Monitor*, kAllocatorTagMonitorList>> Monitors;
diff --git a/runtime/trace.cc b/runtime/trace.cc
index 9d9360e..2add955 100644
--- a/runtime/trace.cc
+++ b/runtime/trace.cc
@@ -54,6 +54,7 @@
static_cast<size_t>(kTraceMethodActionMask));
static constexpr uint8_t kOpNewMethod = 1U;
static constexpr uint8_t kOpNewThread = 2U;
+static constexpr uint8_t kOpTraceSummary = 3U;
class BuildStackTraceVisitor : public StackVisitor {
public:
@@ -700,20 +701,19 @@
std::string header(os.str());
if (trace_output_mode_ == TraceOutputMode::kStreaming) {
- File file(streaming_file_name_ + ".sec", O_CREAT | O_WRONLY, true);
- if (!file.IsOpened()) {
- LOG(WARNING) << "Could not open secondary trace file!";
- return;
- }
- if (!file.WriteFully(header.c_str(), header.length())) {
- file.Erase();
- std::string detail(StringPrintf("Trace data write failed: %s", strerror(errno)));
- PLOG(ERROR) << detail;
- ThrowRuntimeException("%s", detail.c_str());
- }
- if (file.FlushCloseOrErase() != 0) {
- PLOG(ERROR) << "Could not write secondary file";
- }
+ MutexLock mu(Thread::Current(), *streaming_lock_); // To serialize writing.
+ // Write a special token to mark the end of trace records and the start of
+ // trace summary.
+ uint8_t buf[7];
+ Append2LE(buf, 0);
+ buf[2] = kOpTraceSummary;
+ Append4LE(buf + 3, static_cast<uint32_t>(header.length()));
+ WriteToBuf(buf, sizeof(buf));
+ // Write the trace summary. The summary is identical to the file header when
+ // the output mode is not streaming (except for methods).
+ WriteToBuf(reinterpret_cast<const uint8_t*>(header.c_str()), header.length());
+ // Flush the buffer, which may include some trace records before the summary.
+ FlushBuf();
} else {
if (trace_file_.get() == nullptr) {
iovec iov[2];
@@ -894,6 +894,14 @@
memcpy(buf_.get() + old_offset, src, src_size);
}
+void Trace::FlushBuf() {
+ int32_t offset = cur_offset_.LoadRelaxed();
+ if (!trace_file_->WriteFully(buf_.get(), offset)) {
+ PLOG(WARNING) << "Failed flush the remaining data in streaming.";
+ }
+ cur_offset_.StoreRelease(0);
+}
+
void Trace::LogMethodTraceEvent(Thread* thread, ArtMethod* method,
instrumentation::Instrumentation::InstrumentationEvent event,
uint32_t thread_clock_diff, uint32_t wall_clock_diff) {
diff --git a/runtime/trace.h b/runtime/trace.h
index 824b150..485e9a1 100644
--- a/runtime/trace.h
+++ b/runtime/trace.h
@@ -202,7 +202,8 @@
// This causes the negative annotations to incorrectly have a false positive. TODO: Figure out
// how to annotate this.
NO_THREAD_SAFETY_ANALYSIS;
- void FinishTracing() REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!*unique_methods_lock_);
+ void FinishTracing()
+ REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!*unique_methods_lock_, !*streaming_lock_);
void ReadClocks(Thread* thread, uint32_t* thread_clock_diff, uint32_t* wall_clock_diff);
@@ -229,6 +230,9 @@
// annotation.
void WriteToBuf(const uint8_t* src, size_t src_size)
REQUIRES(streaming_lock_);
+ // Flush the main buffer to file. Used for streaming. Exposed here for lock annotation.
+ void FlushBuf()
+ REQUIRES(streaming_lock_);
uint32_t EncodeTraceMethod(ArtMethod* method) REQUIRES(!*unique_methods_lock_);
uint32_t EncodeTraceMethodAndAction(ArtMethod* method, TraceAction action)
diff --git a/test/596-monitor-inflation/expected.txt b/test/596-monitor-inflation/expected.txt
new file mode 100644
index 0000000..2add696
--- /dev/null
+++ b/test/596-monitor-inflation/expected.txt
@@ -0,0 +1,6 @@
+JNI_OnLoad called
+Monitor list grew by at least 4000 monitors
+Monitor list shrank correctly
+Finished first check
+Finished second check
+Total checks: 10000
diff --git a/test/596-monitor-inflation/info.txt b/test/596-monitor-inflation/info.txt
new file mode 100644
index 0000000..81dedb6
--- /dev/null
+++ b/test/596-monitor-inflation/info.txt
@@ -0,0 +1,5 @@
+A simple test that forces many monitors to be inflated, while checking
+that hashcodes are consistently maintained.
+
+This allocates more monitors and hence may exercise the monitor pool
+differently, and with more context, than the monitor_pool_test gtest.
diff --git a/test/596-monitor-inflation/monitor_inflation.cc b/test/596-monitor-inflation/monitor_inflation.cc
new file mode 100644
index 0000000..fb4275b
--- /dev/null
+++ b/test/596-monitor-inflation/monitor_inflation.cc
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2017 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 "gc/heap.h"
+#include "jni.h"
+#include "monitor.h"
+#include "runtime.h"
+#include "thread-inl.h"
+
+namespace art {
+namespace {
+
+extern "C" JNIEXPORT void JNICALL Java_Main_trim(JNIEnv*, jclass) {
+ Runtime::Current()->GetHeap()->Trim(Thread::Current());
+}
+
+extern "C" JNIEXPORT jint JNICALL Java_Main_monitorListSize(JNIEnv*, jclass) {
+ return Runtime::Current()->GetMonitorList()->Size();
+}
+
+} // namespace
+} // namespace art
diff --git a/test/596-monitor-inflation/src/Main.java b/test/596-monitor-inflation/src/Main.java
new file mode 100644
index 0000000..d97c766
--- /dev/null
+++ b/test/596-monitor-inflation/src/Main.java
@@ -0,0 +1,79 @@
+/*
+ * 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.
+ */
+import java.util.IdentityHashMap;
+import dalvik.system.VMRuntime;
+
+public class Main {
+ public static void main(String[] args) {
+ System.loadLibrary(args[0]);
+ int initialSize = monitorListSize();
+ IdentityHashMap<Object, Integer> all = new IdentityHashMap();
+ for (int i = 0; i < 5000; ++i) {
+ Object obj = new Object();
+ synchronized(obj) {
+ // Should force inflation.
+ all.put(obj, obj.hashCode());
+ }
+ }
+ // Since monitor deflation is delayed significantly, we believe that even with an intervening
+ // GC, monitors should remain inflated. We allow some slop for unrelated concurrent runtime
+ // actions.
+ int inflatedSize = monitorListSize();
+ if (inflatedSize >= initialSize + 4000) {
+ System.out.println("Monitor list grew by at least 4000 monitors");
+ } else {
+ System.out.println("Monitor list did not grow as expected");
+ }
+ // Encourage monitor deflation.
+ // trim() (Heap::Trim()) deflates only in JANK_IMPERCEPTIBLE state.
+ // Some of this mirrors code in ActivityThread.java.
+ final int DALVIK_PROCESS_STATE_JANK_PERCEPTIBLE = 0;
+ final int DALVIK_PROCESS_STATE_JANK_IMPERCEPTIBLE = 1;
+ VMRuntime.getRuntime().updateProcessState(DALVIK_PROCESS_STATE_JANK_IMPERCEPTIBLE);
+ System.gc();
+ System.runFinalization();
+ trim();
+ VMRuntime.getRuntime().updateProcessState(DALVIK_PROCESS_STATE_JANK_PERCEPTIBLE);
+ int finalSize = monitorListSize();
+ if (finalSize > initialSize + 1000) {
+ System.out.println("Monitor list failed to shrink properly");
+ } else {
+ System.out.println("Monitor list shrank correctly");
+ }
+ int j = 0;
+ for (Object obj: all.keySet()) {
+ ++j;
+ if (obj.hashCode() != all.get(obj)) {
+ throw new AssertionError("Failed hashcode test!");
+ }
+ }
+ System.out.println("Finished first check");
+ for (Object obj: all.keySet()) {
+ ++j;
+ synchronized(obj) {
+ if (obj.hashCode() != all.get(obj)) {
+ throw new AssertionError("Failed hashcode test!");
+ }
+ }
+ }
+ System.out.println("Finished second check");
+ System.out.println("Total checks: " + j);
+ }
+
+ private static native void trim();
+
+ private static native int monitorListSize();
+}
diff --git a/test/Android.bp b/test/Android.bp
index 9f435dc..89e4092 100644
--- a/test/Android.bp
+++ b/test/Android.bp
@@ -327,6 +327,7 @@
"570-checker-osr/osr.cc",
"595-profile-saving/profile-saving.cc",
"596-app-images/app_images.cc",
+ "596-monitor-inflation/monitor_inflation.cc",
"597-deopt-new-string/deopt.cc",
"626-const-class-linking/clear_dex_cache_types.cc",
],
diff --git a/tools/stream-trace-converter.py b/tools/stream-trace-converter.py
index 951b05b..7e341f2 100755
--- a/tools/stream-trace-converter.py
+++ b/tools/stream-trace-converter.py
@@ -124,12 +124,20 @@
self._threads.append('%d\t%s\n' % (tid, str))
print 'New thread: %d/%s' % (tid, str)
+ def ProcessTraceSummary(self, input):
+ summaryLength = ReadIntLE(input)
+ str = input.read(summaryLength)
+ self._summary = str
+ print 'Summary: \"%s\"' % str
+
def ProcessSpecial(self, input):
code = ord(input.read(1))
if code == 1:
self.ProcessMethod(input)
elif code == 2:
self.ProcessThread(input)
+ elif code == 3:
+ self.ProcessTraceSummary(input)
else:
raise MyException("Unknown special!")
@@ -147,9 +155,24 @@
print 'Buffer underrun, file was probably truncated. Results should still be usable.'
def Finalize(self, header):
- header.write('*threads\n')
- for t in self._threads:
- header.write(t)
+ # If the summary is present in the input file, use it as the header except
+ # for the methods section which is emtpy in the input file. If not present,
+ # apppend header with the threads that are recorded in the input stream.
+ if (self._summary):
+ # Erase the contents that's already written earlier by PrintHeader.
+ header.seek(0)
+ header.truncate()
+ # Copy the lines from the input summary to the output header until
+ # the methods section is seen.
+ for line in self._summary.splitlines(True):
+ if line == "*methods\n":
+ break
+ else:
+ header.write(line)
+ else:
+ header.write('*threads\n')
+ for t in self._threads:
+ header.write(t)
header.write('*methods\n')
for m in self._methods:
header.write(m)
@@ -166,6 +189,7 @@
self._methods = []
self._threads = []
+ self._summary = None
self.Process(input, body)
self.Finalize(header)