summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--compiler/optimizing/instruction_builder.cc54
-rw-r--r--compiler/optimizing/instruction_builder.h1
-rw-r--r--compiler/optimizing/intrinsics_mips64.cc89
-rw-r--r--runtime/class_linker.cc23
-rw-r--r--test/099-vmdebug/src/Main.java6
-rw-r--r--test/444-checker-nce/src/Main.java16
-rw-r--r--test/572-checker-array-get-regression/src/Main.java8
-rw-r--r--tools/ahat/README.txt7
-rw-r--r--tools/ahat/src/AhatSnapshot.java84
-rw-r--r--tools/ahat/src/InstanceUtils.java6
-rw-r--r--tools/ahat/src/ObjectHandler.java8
11 files changed, 204 insertions, 98 deletions
diff --git a/compiler/optimizing/instruction_builder.cc b/compiler/optimizing/instruction_builder.cc
index 12cb826395..00cd2f659d 100644
--- a/compiler/optimizing/instruction_builder.cc
+++ b/compiler/optimizing/instruction_builder.cc
@@ -215,6 +215,17 @@ void HInstructionBuilder::InitializeInstruction(HInstruction* instruction) {
}
}
+HInstruction* HInstructionBuilder::LoadNullCheckedLocal(uint32_t register_index, uint32_t dex_pc) {
+ HInstruction* ref = LoadLocal(register_index, Primitive::kPrimNot);
+ if (!ref->CanBeNull()) {
+ return ref;
+ }
+
+ HNullCheck* null_check = new (arena_) HNullCheck(ref, dex_pc);
+ AppendInstruction(null_check);
+ return null_check;
+}
+
void HInstructionBuilder::SetLoopHeaderPhiInputs() {
for (size_t i = loop_headers_.size(); i > 0; --i) {
HBasicBlock* block = loop_headers_[i - 1];
@@ -1084,10 +1095,9 @@ bool HInstructionBuilder::HandleInvoke(HInvoke* invoke,
size_t start_index = 0;
size_t argument_index = 0;
if (invoke->GetOriginalInvokeType() != InvokeType::kStatic) { // Instance call.
- HInstruction* arg = LoadLocal(is_range ? register_index : args[0], Primitive::kPrimNot);
- HNullCheck* null_check = new (arena_) HNullCheck(arg, invoke->GetDexPc());
- AppendInstruction(null_check);
- invoke->SetArgumentAt(0, null_check);
+ HInstruction* arg = LoadNullCheckedLocal(is_range ? register_index : args[0],
+ invoke->GetDexPc());
+ invoke->SetArgumentAt(0, arg);
start_index = 1;
argument_index = 1;
}
@@ -1193,9 +1203,7 @@ bool HInstructionBuilder::BuildInstanceFieldAccess(const Instruction& instructio
compiler_driver_->ComputeInstanceFieldInfo(field_index, dex_compilation_unit_, is_put, soa);
- HInstruction* object = LoadLocal(obj_reg, Primitive::kPrimNot);
- HInstruction* null_check = new (arena_) HNullCheck(object, dex_pc);
- AppendInstruction(null_check);
+ HInstruction* object = LoadNullCheckedLocal(obj_reg, dex_pc);
Primitive::Type field_type = (resolved_field == nullptr)
? GetFieldAccessType(*dex_file_, field_index)
@@ -1205,14 +1213,14 @@ bool HInstructionBuilder::BuildInstanceFieldAccess(const Instruction& instructio
HInstruction* field_set = nullptr;
if (resolved_field == nullptr) {
MaybeRecordStat(MethodCompilationStat::kUnresolvedField);
- field_set = new (arena_) HUnresolvedInstanceFieldSet(null_check,
+ field_set = new (arena_) HUnresolvedInstanceFieldSet(object,
value,
field_type,
field_index,
dex_pc);
} else {
uint16_t class_def_index = resolved_field->GetDeclaringClass()->GetDexClassDefIndex();
- field_set = new (arena_) HInstanceFieldSet(null_check,
+ field_set = new (arena_) HInstanceFieldSet(object,
value,
field_type,
resolved_field->GetOffset(),
@@ -1228,13 +1236,13 @@ bool HInstructionBuilder::BuildInstanceFieldAccess(const Instruction& instructio
HInstruction* field_get = nullptr;
if (resolved_field == nullptr) {
MaybeRecordStat(MethodCompilationStat::kUnresolvedField);
- field_get = new (arena_) HUnresolvedInstanceFieldGet(null_check,
+ field_get = new (arena_) HUnresolvedInstanceFieldGet(object,
field_type,
field_index,
dex_pc);
} else {
uint16_t class_def_index = resolved_field->GetDeclaringClass()->GetDexClassDefIndex();
- field_get = new (arena_) HInstanceFieldGet(null_check,
+ field_get = new (arena_) HInstanceFieldGet(object,
field_type,
resolved_field->GetOffset(),
resolved_field->IsVolatile(),
@@ -1449,10 +1457,7 @@ void HInstructionBuilder::BuildArrayAccess(const Instruction& instruction,
uint8_t array_reg = instruction.VRegB_23x();
uint8_t index_reg = instruction.VRegC_23x();
- HInstruction* object = LoadLocal(array_reg, Primitive::kPrimNot);
- object = new (arena_) HNullCheck(object, dex_pc);
- AppendInstruction(object);
-
+ HInstruction* object = LoadNullCheckedLocal(array_reg, dex_pc);
HInstruction* length = new (arena_) HArrayLength(object, dex_pc);
AppendInstruction(length);
HInstruction* index = LoadLocal(index_reg, Primitive::kPrimInt);
@@ -1527,11 +1532,8 @@ void HInstructionBuilder::BuildFillArrayData(HInstruction* object,
}
void HInstructionBuilder::BuildFillArrayData(const Instruction& instruction, uint32_t dex_pc) {
- HInstruction* array = LoadLocal(instruction.VRegA_31t(), Primitive::kPrimNot);
- HNullCheck* null_check = new (arena_) HNullCheck(array, dex_pc);
- AppendInstruction(null_check);
-
- HInstruction* length = new (arena_) HArrayLength(null_check, dex_pc);
+ HInstruction* array = LoadNullCheckedLocal(instruction.VRegA_31t(), dex_pc);
+ HInstruction* length = new (arena_) HArrayLength(array, dex_pc);
AppendInstruction(length);
int32_t payload_offset = instruction.VRegB_31t() + dex_pc;
@@ -1547,28 +1549,28 @@ void HInstructionBuilder::BuildFillArrayData(const Instruction& instruction, uin
switch (payload->element_width) {
case 1:
- BuildFillArrayData(null_check,
+ BuildFillArrayData(array,
reinterpret_cast<const int8_t*>(data),
element_count,
Primitive::kPrimByte,
dex_pc);
break;
case 2:
- BuildFillArrayData(null_check,
+ BuildFillArrayData(array,
reinterpret_cast<const int16_t*>(data),
element_count,
Primitive::kPrimShort,
dex_pc);
break;
case 4:
- BuildFillArrayData(null_check,
+ BuildFillArrayData(array,
reinterpret_cast<const int32_t*>(data),
element_count,
Primitive::kPrimInt,
dex_pc);
break;
case 8:
- BuildFillWideArrayData(null_check,
+ BuildFillWideArrayData(array,
reinterpret_cast<const int64_t*>(data),
element_count,
dex_pc);
@@ -2575,9 +2577,7 @@ bool HInstructionBuilder::ProcessDexInstruction(const Instruction& instruction,
ARRAY_XX(_SHORT, Primitive::kPrimShort);
case Instruction::ARRAY_LENGTH: {
- HInstruction* object = LoadLocal(instruction.VRegB_12x(), Primitive::kPrimNot);
- object = new (arena_) HNullCheck(object, dex_pc);
- AppendInstruction(object);
+ HInstruction* object = LoadNullCheckedLocal(instruction.VRegB_12x(), dex_pc);
AppendInstruction(new (arena_) HArrayLength(object, dex_pc));
UpdateLocal(instruction.VRegA_12x(), current_block_->GetLastInstruction());
break;
diff --git a/compiler/optimizing/instruction_builder.h b/compiler/optimizing/instruction_builder.h
index 070f7da80e..0e3e5a7c34 100644
--- a/compiler/optimizing/instruction_builder.h
+++ b/compiler/optimizing/instruction_builder.h
@@ -87,6 +87,7 @@ class HInstructionBuilder : public ValueObject {
ArenaVector<HInstruction*>* GetLocalsFor(HBasicBlock* block);
HInstruction* ValueOfLocalAt(HBasicBlock* block, size_t local);
HInstruction* LoadLocal(uint32_t register_index, Primitive::Type type) const;
+ HInstruction* LoadNullCheckedLocal(uint32_t register_index, uint32_t dex_pc);
void UpdateLocal(uint32_t register_index, HInstruction* instruction);
void AppendInstruction(HInstruction* instruction);
diff --git a/compiler/optimizing/intrinsics_mips64.cc b/compiler/optimizing/intrinsics_mips64.cc
index cf973aa841..1524e1e011 100644
--- a/compiler/optimizing/intrinsics_mips64.cc
+++ b/compiler/optimizing/intrinsics_mips64.cc
@@ -385,6 +385,92 @@ static void CreateFPToFPLocations(ArenaAllocator* arena, HInvoke* invoke) {
locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
}
+static void GenBitCount(LocationSummary* locations,
+ const Primitive::Type type,
+ Mips64Assembler* assembler) {
+ GpuRegister out = locations->Out().AsRegister<GpuRegister>();
+ GpuRegister in = locations->InAt(0).AsRegister<GpuRegister>();
+
+ DCHECK(type == Primitive::kPrimInt || type == Primitive::kPrimLong);
+
+ // https://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetParallel
+ //
+ // A generalization of the best bit counting method to integers of
+ // bit-widths up to 128 (parameterized by type T) is this:
+ //
+ // v = v - ((v >> 1) & (T)~(T)0/3); // temp
+ // v = (v & (T)~(T)0/15*3) + ((v >> 2) & (T)~(T)0/15*3); // temp
+ // v = (v + (v >> 4)) & (T)~(T)0/255*15; // temp
+ // c = (T)(v * ((T)~(T)0/255)) >> (sizeof(T) - 1) * BITS_PER_BYTE; // count
+ //
+ // For comparison, for 32-bit quantities, this algorithm can be executed
+ // using 20 MIPS instructions (the calls to LoadConst32() generate two
+ // machine instructions each for the values being used in this algorithm).
+ // A(n unrolled) loop-based algorithm requires 25 instructions.
+ //
+ // For a 64-bit operand this can be performed in 24 instructions compared
+ // to a(n unrolled) loop based algorithm which requires 38 instructions.
+ //
+ // There are algorithms which are faster in the cases where very few
+ // bits are set but the algorithm here attempts to minimize the total
+ // number of instructions executed even when a large number of bits
+ // are set.
+
+ if (type == Primitive::kPrimInt) {
+ __ Srl(TMP, in, 1);
+ __ LoadConst32(AT, 0x55555555);
+ __ And(TMP, TMP, AT);
+ __ Subu(TMP, in, TMP);
+ __ LoadConst32(AT, 0x33333333);
+ __ And(out, TMP, AT);
+ __ Srl(TMP, TMP, 2);
+ __ And(TMP, TMP, AT);
+ __ Addu(TMP, out, TMP);
+ __ Srl(out, TMP, 4);
+ __ Addu(out, out, TMP);
+ __ LoadConst32(AT, 0x0F0F0F0F);
+ __ And(out, out, AT);
+ __ LoadConst32(TMP, 0x01010101);
+ __ MulR6(out, out, TMP);
+ __ Srl(out, out, 24);
+ } else if (type == Primitive::kPrimLong) {
+ __ Dsrl(TMP, in, 1);
+ __ LoadConst64(AT, 0x5555555555555555L);
+ __ And(TMP, TMP, AT);
+ __ Dsubu(TMP, in, TMP);
+ __ LoadConst64(AT, 0x3333333333333333L);
+ __ And(out, TMP, AT);
+ __ Dsrl(TMP, TMP, 2);
+ __ And(TMP, TMP, AT);
+ __ Daddu(TMP, out, TMP);
+ __ Dsrl(out, TMP, 4);
+ __ Daddu(out, out, TMP);
+ __ LoadConst64(AT, 0x0F0F0F0F0F0F0F0FL);
+ __ And(out, out, AT);
+ __ LoadConst64(TMP, 0x0101010101010101L);
+ __ Dmul(out, out, TMP);
+ __ Dsrl32(out, out, 24);
+ }
+}
+
+// int java.lang.Integer.bitCount(int)
+void IntrinsicLocationsBuilderMIPS64::VisitIntegerBitCount(HInvoke* invoke) {
+ CreateIntToIntLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorMIPS64::VisitIntegerBitCount(HInvoke* invoke) {
+ GenBitCount(invoke->GetLocations(), Primitive::kPrimInt, GetAssembler());
+}
+
+// int java.lang.Long.bitCount(long)
+void IntrinsicLocationsBuilderMIPS64::VisitLongBitCount(HInvoke* invoke) {
+ CreateIntToIntLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorMIPS64::VisitLongBitCount(HInvoke* invoke) {
+ GenBitCount(invoke->GetLocations(), Primitive::kPrimLong, GetAssembler());
+}
+
static void MathAbsFP(LocationSummary* locations, bool is64bit, Mips64Assembler* assembler) {
FpuRegister in = locations->InAt(0).AsFpuRegister<FpuRegister>();
FpuRegister out = locations->Out().AsFpuRegister<FpuRegister>();
@@ -1693,9 +1779,6 @@ void IntrinsicCodeGeneratorMIPS64::VisitDoubleIsInfinite(HInvoke* invoke) {
GenIsInfinite(invoke->GetLocations(), /* is64bit */ true, GetAssembler());
}
-UNIMPLEMENTED_INTRINSIC(MIPS64, IntegerBitCount)
-UNIMPLEMENTED_INTRINSIC(MIPS64, LongBitCount)
-
UNIMPLEMENTED_INTRINSIC(MIPS64, MathRoundDouble)
UNIMPLEMENTED_INTRINSIC(MIPS64, MathRoundFloat)
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 1e7ee65eac..fa0107af8e 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -4442,7 +4442,20 @@ bool ClassLinker::InitializeClass(Thread* self, Handle<mirror::Class> klass,
// We failed to verify, expect either the klass to be erroneous or verification failed at
// compile time.
if (klass->IsErroneous()) {
- CHECK(self->IsExceptionPending());
+ // The class is erroneous. This may be a verifier error, or another thread attempted
+ // verification and/or initialization and failed. We can distinguish those cases by
+ // whether an exception is already pending.
+ if (self->IsExceptionPending()) {
+ // Check that it's a VerifyError.
+ DCHECK_EQ("java.lang.Class<java.lang.VerifyError>",
+ PrettyClass(self->GetException()->GetClass()));
+ } else {
+ // Check that another thread attempted initialization.
+ DCHECK_NE(0, klass->GetClinitThreadId());
+ DCHECK_NE(self->GetTid(), klass->GetClinitThreadId());
+ // Need to rethrow the previous failure now.
+ ThrowEarlierClassFailure(klass.Get(), true);
+ }
VlogClassInitializationFailure(klass);
} else {
CHECK(Runtime::Current()->IsAotCompiler());
@@ -4452,6 +4465,14 @@ bool ClassLinker::InitializeClass(Thread* self, Handle<mirror::Class> klass,
} else {
self->AssertNoPendingException();
}
+
+ // A separate thread could have moved us all the way to initialized. A "simple" example
+ // involves a subclass of the current class being initialized at the same time (which
+ // will implicitly initialize the superclass, if scheduled that way). b/28254258
+ DCHECK_NE(mirror::Class::kStatusError, klass->GetStatus());
+ if (klass->IsInitialized()) {
+ return true;
+ }
}
// If the class is kStatusInitializing, either this thread is
diff --git a/test/099-vmdebug/src/Main.java b/test/099-vmdebug/src/Main.java
index 1be5765155..8068721219 100644
--- a/test/099-vmdebug/src/Main.java
+++ b/test/099-vmdebug/src/Main.java
@@ -133,7 +133,7 @@ public class Main {
System.out.println("Got null string");
return;
}
- long n = Long.valueOf(s);
+ long n = Long.parseLong(s);
if (n < 0) {
System.out.println("Got negative number " + n);
}
@@ -157,8 +157,8 @@ public class Main {
System.out.println("Got bad bucket " + bucket);
continue;
}
- long key = Long.valueOf(kv[0]);
- long value = Long.valueOf(kv[1]);
+ long key = Long.parseLong(kv[0]);
+ long value = Long.parseLong(kv[1]);
if (key < 0 || value < 0) {
System.out.println("Got negative key or value " + bucket);
continue;
diff --git a/test/444-checker-nce/src/Main.java b/test/444-checker-nce/src/Main.java
index c96b18c71b..ddc2f77e89 100644
--- a/test/444-checker-nce/src/Main.java
+++ b/test/444-checker-nce/src/Main.java
@@ -28,10 +28,6 @@ public class Main {
}
/// CHECK-START: Main Main.thisTest() builder (after)
- /// CHECK: NullCheck
- /// CHECK: InvokeStaticOrDirect
-
- /// CHECK-START: Main Main.thisTest() instruction_simplifier (after)
/// CHECK-NOT: NullCheck
/// CHECK: InvokeStaticOrDirect
public Main thisTest() {
@@ -40,12 +36,10 @@ public class Main {
/// CHECK-START: Main Main.newInstanceRemoveTest() builder (after)
/// CHECK: NewInstance
- /// CHECK: NullCheck
/// CHECK: InvokeStaticOrDirect
- /// CHECK: NullCheck
/// CHECK: InvokeStaticOrDirect
- /// CHECK-START: Main Main.newInstanceRemoveTest() instruction_simplifier (after)
+ /// CHECK-START: Main Main.newInstanceRemoveTest() builder (after)
/// CHECK-NOT: NullCheck
public Main newInstanceRemoveTest() {
Main m = new Main();
@@ -54,13 +48,10 @@ public class Main {
/// CHECK-START: Main Main.newArrayRemoveTest() builder (after)
/// CHECK: NewArray
- /// CHECK: NullCheck
/// CHECK: ArrayGet
- /// CHECK-START: Main Main.newArrayRemoveTest() instruction_simplifier (after)
- /// CHECK: NewArray
+ /// CHECK-START: Main Main.newArrayRemoveTest() builder (after)
/// CHECK-NOT: NullCheck
- /// CHECK: ArrayGet
public Main newArrayRemoveTest() {
Main[] ms = new Main[1];
return ms[0];
@@ -179,9 +170,6 @@ public class Main {
}
/// CHECK-START: Main Main.scopeRemoveTest(int, Main) builder (after)
- /// CHECK: NullCheck
-
- /// CHECK-START: Main Main.scopeRemoveTest(int, Main) instruction_simplifier (after)
/// CHECK-NOT: NullCheck
public Main scopeRemoveTest(int count, Main a) {
Main m = null;
diff --git a/test/572-checker-array-get-regression/src/Main.java b/test/572-checker-array-get-regression/src/Main.java
index b55be706f4..89b97ed316 100644
--- a/test/572-checker-array-get-regression/src/Main.java
+++ b/test/572-checker-array-get-regression/src/Main.java
@@ -25,13 +25,11 @@ public class Main {
/// CHECK-DAG: <<Const2P19:i\d+>> IntConstant 524288
/// CHECK-DAG: <<ConstM1:i\d+>> IntConstant -1
/// CHECK-DAG: <<Array:l\d+>> NewArray [<<Const2P19>>,<<Method>>]
- /// CHECK-DAG: <<NullCheck1:l\d+>> NullCheck [<<Array>>]
- /// CHECK-DAG: <<Length1:i\d+>> ArrayLength [<<NullCheck1>>]
+ /// CHECK-DAG: <<Length1:i\d+>> ArrayLength [<<Array>>]
/// CHECK-DAG: <<Index:i\d+>> Add [<<Length1>>,<<ConstM1>>]
- /// CHECK-DAG: <<NullCheck2:l\d+>> NullCheck [<<Array>>]
- /// CHECK-DAG: <<Length2:i\d+>> ArrayLength [<<NullCheck2>>]
+ /// CHECK-DAG: <<Length2:i\d+>> ArrayLength [<<Array>>]
/// CHECK-DAG: <<BoundsCheck:i\d+>> BoundsCheck [<<Index>>,<<Length2>>]
- /// CHECK-DAG: <<LastElement:l\d+>> ArrayGet [<<NullCheck2>>,<<BoundsCheck>>]
+ /// CHECK-DAG: <<LastElement:l\d+>> ArrayGet [<<Array>>,<<BoundsCheck>>]
/// CHECK-DAG: Return [<<LastElement>>]
diff --git a/tools/ahat/README.txt b/tools/ahat/README.txt
index d9b26bcf58..0cd77ab69d 100644
--- a/tools/ahat/README.txt
+++ b/tools/ahat/README.txt
@@ -77,7 +77,12 @@ Things to move to perflib:
* Instance.isRoot and Instance.getRootTypes.
Release History:
- 0.4 Pending
+ 0.6 Pending
+
+ 0.5 Apr 19, 2016
+ Update perflib to perflib-25.0.0 to improve processing performance.
+
+ 0.4 Feb 23, 2016
Annotate char[] objects with their string values.
Show registered native allocations for heap dumps that support it.
diff --git a/tools/ahat/src/AhatSnapshot.java b/tools/ahat/src/AhatSnapshot.java
index 2adec6f17b..d088e8c43f 100644
--- a/tools/ahat/src/AhatSnapshot.java
+++ b/tools/ahat/src/AhatSnapshot.java
@@ -25,8 +25,8 @@ import com.android.tools.perflib.heap.Snapshot;
import com.android.tools.perflib.heap.StackFrame;
import com.android.tools.perflib.heap.StackTrace;
import com.android.tools.perflib.captures.MemoryMappedFileBuffer;
-import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
+import gnu.trove.TObjectProcedure;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
@@ -85,49 +85,59 @@ class AhatSnapshot {
ClassObj javaLangClass = mSnapshot.findClass("java.lang.Class");
for (Heap heap : mHeaps) {
- long total = 0;
- for (Instance inst : Iterables.concat(heap.getClasses(), heap.getInstances())) {
- Instance dominator = inst.getImmediateDominator();
- if (dominator != null) {
- total += inst.getSize();
-
- if (dominator == Snapshot.SENTINEL_ROOT) {
- mRooted.add(inst);
- }
+ // Use a single element array for the total to act as a reference to a
+ // long.
+ final long[] total = new long[]{0};
+ TObjectProcedure<Instance> processInstance = new TObjectProcedure<Instance>() {
+ @Override
+ public boolean execute(Instance inst) {
+ Instance dominator = inst.getImmediateDominator();
+ if (dominator != null) {
+ total[0] += inst.getSize();
+
+ if (dominator == Snapshot.SENTINEL_ROOT) {
+ mRooted.add(inst);
+ }
- // Properly label the class of a class object.
- if (inst instanceof ClassObj && javaLangClass != null && inst.getClassObj() == null) {
- inst.setClassId(javaLangClass.getId());
- }
+ // Properly label the class of a class object.
+ if (inst instanceof ClassObj && javaLangClass != null && inst.getClassObj() == null) {
+ inst.setClassId(javaLangClass.getId());
+ }
- // Update dominated instances.
- List<Instance> instances = mDominated.get(dominator);
- if (instances == null) {
- instances = new ArrayList<Instance>();
- mDominated.put(dominator, instances);
- }
- instances.add(inst);
-
- // Update sites.
- List<StackFrame> path = Collections.emptyList();
- StackTrace stack = getStack(inst);
- int stackId = getStackTraceSerialNumber(stack);
- if (stack != null) {
- StackFrame[] frames = getStackFrames(stack);
- if (frames != null && frames.length > 0) {
- path = Lists.reverse(Arrays.asList(frames));
+ // Update dominated instances.
+ List<Instance> instances = mDominated.get(dominator);
+ if (instances == null) {
+ instances = new ArrayList<Instance>();
+ mDominated.put(dominator, instances);
}
- }
- mRootSite.add(stackId, 0, path.iterator(), inst);
+ instances.add(inst);
+
+ // Update sites.
+ List<StackFrame> path = Collections.emptyList();
+ StackTrace stack = getStack(inst);
+ int stackId = getStackTraceSerialNumber(stack);
+ if (stack != null) {
+ StackFrame[] frames = getStackFrames(stack);
+ if (frames != null && frames.length > 0) {
+ path = Lists.reverse(Arrays.asList(frames));
+ }
+ }
+ mRootSite.add(stackId, 0, path.iterator(), inst);
- // Update native allocations.
- InstanceUtils.NativeAllocation alloc = InstanceUtils.getNativeAllocation(inst);
- if (alloc != null) {
- mNativeAllocations.add(alloc);
+ // Update native allocations.
+ InstanceUtils.NativeAllocation alloc = InstanceUtils.getNativeAllocation(inst);
+ if (alloc != null) {
+ mNativeAllocations.add(alloc);
+ }
}
+ return true;
}
+ };
+ for (Instance instance : heap.getClasses()) {
+ processInstance.execute(instance);
}
- mHeapSizes.put(heap, total);
+ heap.forEachInstance(processInstance);
+ mHeapSizes.put(heap, total[0]);
}
// Record the roots and their types.
diff --git a/tools/ahat/src/InstanceUtils.java b/tools/ahat/src/InstanceUtils.java
index d7b64e2afd..8defba2647 100644
--- a/tools/ahat/src/InstanceUtils.java
+++ b/tools/ahat/src/InstanceUtils.java
@@ -244,8 +244,8 @@ class InstanceUtils {
if (inst instanceof ArrayInstance) {
ArrayInstance array = (ArrayInstance)inst;
- if (array.getArrayType() == Type.BYTE && inst.getHardReferences().size() == 1) {
- Instance ref = inst.getHardReferences().get(0);
+ if (array.getArrayType() == Type.BYTE && inst.getHardReverseReferences().size() == 1) {
+ Instance ref = inst.getHardReverseReferences().get(0);
ClassObj clsref = ref.getClassObj();
if (clsref != null && "android.graphics.Bitmap".equals(clsref.getClassName())) {
return ref;
@@ -344,7 +344,7 @@ class InstanceUtils {
}
Instance referent = null;
- for (Instance ref : inst.getHardReferences()) {
+ for (Instance ref : inst.getHardReverseReferences()) {
if (isInstanceOfClass(ref, "sun.misc.Cleaner")) {
referent = InstanceUtils.getReferent(ref);
if (referent != null) {
diff --git a/tools/ahat/src/ObjectHandler.java b/tools/ahat/src/ObjectHandler.java
index 06023dab7f..4df1be5ac2 100644
--- a/tools/ahat/src/ObjectHandler.java
+++ b/tools/ahat/src/ObjectHandler.java
@@ -160,11 +160,11 @@ class ObjectHandler implements AhatHandler {
private static void printReferences(
Doc doc, Query query, AhatSnapshot snapshot, Instance inst) {
doc.section("Objects with References to this Object");
- if (inst.getHardReferences().isEmpty()) {
+ if (inst.getHardReverseReferences().isEmpty()) {
doc.println(DocString.text("(none)"));
} else {
doc.table(new Column("Object"));
- List<Instance> references = inst.getHardReferences();
+ List<Instance> references = inst.getHardReverseReferences();
SubsetSelector<Instance> selector = new SubsetSelector(query, HARD_REFS_ID, references);
for (Instance ref : selector.selected()) {
doc.row(Value.render(snapshot, ref));
@@ -173,10 +173,10 @@ class ObjectHandler implements AhatHandler {
selector.render(doc);
}
- if (inst.getSoftReferences() != null) {
+ if (inst.getSoftReverseReferences() != null) {
doc.section("Objects with Soft References to this Object");
doc.table(new Column("Object"));
- List<Instance> references = inst.getSoftReferences();
+ List<Instance> references = inst.getSoftReverseReferences();
SubsetSelector<Instance> selector = new SubsetSelector(query, SOFT_REFS_ID, references);
for (Instance ref : selector.selected()) {
doc.row(Value.render(snapshot, ref));