Merge "Workaround problem reading main stack on intel devices."
diff --git a/compiler/dex/global_value_numbering.cc b/compiler/dex/global_value_numbering.cc
index d7ef6f0..3575ade 100644
--- a/compiler/dex/global_value_numbering.cc
+++ b/compiler/dex/global_value_numbering.cc
@@ -56,8 +56,11 @@
return nullptr;
}
if (UNLIKELY(bbs_processed_ == max_bbs_to_process_)) {
- last_value_ = kNoValue; // Make bad.
- return nullptr;
+ // If we're still trying to converge, stop now. Otherwise, proceed to apply optimizations.
+ if (!modifications_allowed_) {
+ last_value_ = kNoValue; // Make bad.
+ return nullptr;
+ }
}
if (allocator == nullptr) {
allocator = allocator_;
diff --git a/compiler/dex/global_value_numbering.h b/compiler/dex/global_value_numbering.h
index c06ff6f..1a38692 100644
--- a/compiler/dex/global_value_numbering.h
+++ b/compiler/dex/global_value_numbering.h
@@ -214,7 +214,7 @@
static constexpr uint32_t kMaxBbsToProcessMultiplyFactor = 20u;
uint32_t bbs_processed_;
- uint32_t max_bbs_to_process_;
+ uint32_t max_bbs_to_process_; // Doesn't apply after the main GVN has converged.
// We have 32-bit last_value_ so that we can detect when we run out of value names, see Good().
// We usually don't check Good() until the end of LVN unless we're about to modify code.
diff --git a/compiler/dex/local_value_numbering.cc b/compiler/dex/local_value_numbering.cc
index 5997568..8b02269 100644
--- a/compiler/dex/local_value_numbering.cc
+++ b/compiler/dex/local_value_numbering.cc
@@ -656,13 +656,37 @@
}
}
-void LocalValueNumbering::MergeNullChecked(const ValueNameSet::value_type& entry,
- ValueNameSet::iterator hint) {
- // Merge null_checked_ for this ref.
- merge_names_.clear();
- merge_names_.resize(gvn_->merge_lvns_.size(), entry);
- if (gvn_->NullCheckedInAllPredecessors(merge_names_)) {
- null_checked_.insert(hint, entry);
+void LocalValueNumbering::MergeNullChecked() {
+ DCHECK_GE(gvn_->merge_lvns_.size(), 2u);
+
+ // Find the LVN with the least entries in the set.
+ const LocalValueNumbering* least_entries_lvn = gvn_->merge_lvns_[0];
+ for (const LocalValueNumbering* lvn : gvn_->merge_lvns_) {
+ if (lvn->null_checked_.size() < least_entries_lvn->null_checked_.size()) {
+ least_entries_lvn = lvn;
+ }
+ }
+
+ // For each null-checked value name check if it's null-checked in all the LVNs.
+ for (const auto& value_name : least_entries_lvn->null_checked_) {
+ // Merge null_checked_ for this ref.
+ merge_names_.clear();
+ merge_names_.resize(gvn_->merge_lvns_.size(), value_name);
+ if (gvn_->NullCheckedInAllPredecessors(merge_names_)) {
+ null_checked_.insert(null_checked_.end(), value_name);
+ }
+ }
+
+ // Now check if the least_entries_lvn has a null-check as the last insn.
+ const BasicBlock* least_entries_bb = gvn_->GetBasicBlock(least_entries_lvn->Id());
+ if (gvn_->HasNullCheckLastInsn(least_entries_bb, id_)) {
+ int s_reg = least_entries_bb->last_mir_insn->ssa_rep->uses[0];
+ uint32_t value_name = least_entries_lvn->GetSRegValueName(s_reg);
+ merge_names_.clear();
+ merge_names_.resize(gvn_->merge_lvns_.size(), value_name);
+ if (gvn_->NullCheckedInAllPredecessors(merge_names_)) {
+ null_checked_.insert(value_name);
+ }
}
}
@@ -896,8 +920,7 @@
IntersectSets<RangeCheckSet, &LocalValueNumbering::range_checked_>();
// Merge null_checked_. We may later insert more, such as merged object field values.
- MergeSets<ValueNameSet, &LocalValueNumbering::null_checked_,
- &LocalValueNumbering::MergeNullChecked>();
+ MergeNullChecked();
if (merge_type == kCatchMerge) {
// Memory is clobbered. New memory version already created, don't merge aliasing locations.
diff --git a/compiler/dex/local_value_numbering.h b/compiler/dex/local_value_numbering.h
index 855d66d..f6a454b 100644
--- a/compiler/dex/local_value_numbering.h
+++ b/compiler/dex/local_value_numbering.h
@@ -343,11 +343,11 @@
EscapedIFieldClobberSet::iterator hint);
void MergeEscapedArrayClobberSets(const EscapedArrayClobberSet::value_type& entry,
EscapedArrayClobberSet::iterator hint);
- void MergeNullChecked(const ValueNameSet::value_type& entry, ValueNameSet::iterator hint);
void MergeSFieldValues(const SFieldToValueMap::value_type& entry,
SFieldToValueMap::iterator hint);
void MergeNonAliasingIFieldValues(const IFieldLocToValueMap::value_type& entry,
IFieldLocToValueMap::iterator hint);
+ void MergeNullChecked();
template <typename Map, Map LocalValueNumbering::*map_ptr, typename Versions>
void MergeAliasingValues(const typename Map::value_type& entry, typename Map::iterator hint);
diff --git a/compiler/dex/quick/arm64/call_arm64.cc b/compiler/dex/quick/arm64/call_arm64.cc
index 0538c31..eddc3a3 100644
--- a/compiler/dex/quick/arm64/call_arm64.cc
+++ b/compiler/dex/quick/arm64/call_arm64.cc
@@ -208,9 +208,9 @@
OpRegRegImm(kOpAdd, rs_x2, rs_x0, mirror::Object::MonitorOffset().Int32Value());
NewLIR2(kA64Ldxr2rX, rw3, rx2);
MarkPossibleNullPointerException(opt_flags);
- LIR* not_unlocked_branch = OpCmpImmBranch(kCondNe, rs_x1, 0, NULL);
+ LIR* not_unlocked_branch = OpCmpImmBranch(kCondNe, rs_w3, 0, NULL);
NewLIR3(kA64Stxr3wrX, rw3, rw1, rx2);
- LIR* lock_success_branch = OpCmpImmBranch(kCondEq, rs_x1, 0, NULL);
+ LIR* lock_success_branch = OpCmpImmBranch(kCondEq, rs_w3, 0, NULL);
LIR* slow_path_target = NewLIR0(kPseudoTargetLabel);
not_unlocked_branch->target = slow_path_target;
diff --git a/compiler/dex/quick/x86/target_x86.cc b/compiler/dex/quick/x86/target_x86.cc
index f4bb40c..833052d 100755
--- a/compiler/dex/quick/x86/target_x86.cc
+++ b/compiler/dex/quick/x86/target_x86.cc
@@ -1329,10 +1329,12 @@
if (!cu_->target64 && rl_start.location != kLocPhysReg) {
// Load the start index from stack, remembering that we pushed EDI.
int displacement = SRegOffset(rl_start.s_reg_low) + sizeof(uint32_t);
- {
- ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
- Load32Disp(rs_rX86_SP, displacement, rs_rDI);
- }
+ ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg);
+ Load32Disp(rs_rX86_SP, displacement, rs_rDI);
+ // Dalvik register annotation in LoadBaseIndexedDisp() used wrong offset. Fix it.
+ DCHECK(!DECODE_ALIAS_INFO_WIDE(last_lir_insn_->flags.alias_info));
+ int reg_id = DECODE_ALIAS_INFO_REG(last_lir_insn_->flags.alias_info) - 1;
+ AnnotateDalvikRegAccess(last_lir_insn_, reg_id, true, false);
} else {
LoadValueDirectFixed(rl_start, rs_rDI);
}
diff --git a/compiler/optimizing/code_generator.h b/compiler/optimizing/code_generator.h
index 24e0277..12337c9 100644
--- a/compiler/optimizing/code_generator.h
+++ b/compiler/optimizing/code_generator.h
@@ -143,7 +143,7 @@
protected:
CodeGenerator(HGraph* graph, size_t number_of_registers)
: frame_size_(kUninitializedFrameSize),
- core_spill_mask_(-1),
+ core_spill_mask_(0),
graph_(graph),
block_labels_(graph->GetArena(), 0),
pc_infos_(graph->GetArena(), 32),
diff --git a/runtime/gc/accounting/mod_union_table.cc b/runtime/gc/accounting/mod_union_table.cc
index 2686af0..3acf80d 100644
--- a/runtime/gc/accounting/mod_union_table.cc
+++ b/runtime/gc/accounting/mod_union_table.cc
@@ -72,9 +72,11 @@
class ModUnionUpdateObjectReferencesVisitor {
public:
- ModUnionUpdateObjectReferencesVisitor(MarkHeapReferenceCallback* callback, void* arg)
- : callback_(callback),
- arg_(arg) {
+ ModUnionUpdateObjectReferencesVisitor(MarkHeapReferenceCallback* callback, void* arg,
+ space::ContinuousSpace* from_space,
+ bool* contains_reference_to_other_space)
+ : callback_(callback), arg_(arg), from_space_(from_space),
+ contains_reference_to_other_space_(contains_reference_to_other_space) {
}
// Extra parameters are required since we use this same visitor signature for checking objects.
@@ -82,7 +84,9 @@
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
// Only add the reference if it is non null and fits our criteria.
mirror::HeapReference<Object>* obj_ptr = obj->GetFieldObjectReferenceAddr(offset);
- if (obj_ptr->AsMirrorPtr() != nullptr) {
+ mirror::Object* ref = obj_ptr->AsMirrorPtr();
+ if (ref != nullptr && !from_space_->HasAddress(ref)) {
+ *contains_reference_to_other_space_ = true;
callback_(obj_ptr, arg_);
}
}
@@ -90,24 +94,36 @@
private:
MarkHeapReferenceCallback* const callback_;
void* arg_;
+ // Space which we are scanning
+ space::ContinuousSpace* const from_space_;
+ // Set if we have any references to another space.
+ bool* const contains_reference_to_other_space_;
};
class ModUnionScanImageRootVisitor {
public:
- ModUnionScanImageRootVisitor(MarkHeapReferenceCallback* callback, void* arg)
- : callback_(callback), arg_(arg) {}
+ ModUnionScanImageRootVisitor(MarkHeapReferenceCallback* callback, void* arg,
+ space::ContinuousSpace* from_space,
+ bool* contains_reference_to_other_space)
+ : callback_(callback), arg_(arg), from_space_(from_space),
+ contains_reference_to_other_space_(contains_reference_to_other_space) {}
void operator()(Object* root) const
EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
DCHECK(root != NULL);
- ModUnionUpdateObjectReferencesVisitor ref_visitor(callback_, arg_);
+ ModUnionUpdateObjectReferencesVisitor ref_visitor(callback_, arg_, from_space_,
+ contains_reference_to_other_space_);
root->VisitReferences<kMovingClasses>(ref_visitor, VoidFunctor());
}
private:
MarkHeapReferenceCallback* const callback_;
void* const arg_;
+ // Space which we are scanning
+ space::ContinuousSpace* const from_space_;
+ // Set if we have any references to another space.
+ bool* const contains_reference_to_other_space_;
};
void ModUnionTableReferenceCache::ClearCards() {
@@ -313,12 +329,20 @@
void ModUnionTableCardCache::UpdateAndMarkReferences(MarkHeapReferenceCallback* callback,
void* arg) {
CardTable* card_table = heap_->GetCardTable();
- ModUnionScanImageRootVisitor scan_visitor(callback, arg);
ContinuousSpaceBitmap* bitmap = space_->GetLiveBitmap();
- for (const byte* card_addr : cleared_cards_) {
- uintptr_t start = reinterpret_cast<uintptr_t>(card_table->AddrFromCard(card_addr));
+ bool reference_to_other_space = false;
+ ModUnionScanImageRootVisitor scan_visitor(callback, arg, space_, &reference_to_other_space);
+ for (auto it = cleared_cards_.begin(), end = cleared_cards_.end(); it != end; ) {
+ uintptr_t start = reinterpret_cast<uintptr_t>(card_table->AddrFromCard(*it));
DCHECK(space_->HasAddress(reinterpret_cast<Object*>(start)));
+ reference_to_other_space = false;
bitmap->VisitMarkedRange(start, start + CardTable::kCardSize, scan_visitor);
+ if (!reference_to_other_space) {
+ // No non null reference to another space, remove the card.
+ it = cleared_cards_.erase(it);
+ } else {
+ ++it;
+ }
}
}
@@ -333,6 +357,17 @@
os << "]";
}
+void ModUnionTableCardCache::SetCards() {
+ CardTable* card_table = heap_->GetCardTable();
+ for (byte* addr = space_->Begin(); addr < AlignUp(space_->End(), CardTable::kCardSize);
+ addr += CardTable::kCardSize) {
+ cleared_cards_.insert(card_table->CardFromAddr(addr));
+ }
+}
+
+void ModUnionTableReferenceCache::SetCards() {
+}
+
} // namespace accounting
} // namespace gc
} // namespace art
diff --git a/runtime/gc/accounting/mod_union_table.h b/runtime/gc/accounting/mod_union_table.h
index 449e171..f67dc27 100644
--- a/runtime/gc/accounting/mod_union_table.h
+++ b/runtime/gc/accounting/mod_union_table.h
@@ -65,6 +65,9 @@
// determining references to track.
virtual void ClearCards() = 0;
+ // Set all the cards.
+ virtual void SetCards() = 0;
+
// Update the mod-union table using data stored by ClearCards. There may be multiple ClearCards
// before a call to update, for example, back-to-back sticky GCs. Also mark references to other
// spaces which are stored in the mod-union table.
@@ -120,6 +123,8 @@
void Dump(std::ostream& os) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ void SetCards() OVERRIDE;
+
protected:
// Cleared card array, used to update the mod-union table.
ModUnionTable::CardSet cleared_cards_;
@@ -150,6 +155,8 @@
void Dump(std::ostream& os);
+ void SetCards() OVERRIDE;
+
protected:
// Cleared card array, used to update the mod-union table.
CardSet cleared_cards_;
diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc
index 821d22f..f0b7685 100644
--- a/runtime/gc/heap.cc
+++ b/runtime/gc/heap.cc
@@ -128,8 +128,8 @@
long_gc_log_threshold_(long_gc_log_threshold),
ignore_max_footprint_(ignore_max_footprint),
zygote_creation_lock_("zygote creation lock", kZygoteCreationLock),
- have_zygote_space_(false),
- large_object_threshold_(std::numeric_limits<size_t>::max()), // Starts out disabled.
+ zygote_space_(nullptr),
+ large_object_threshold_(kDefaultLargeObjectThreshold), // Starts out disabled.
collector_type_running_(kCollectorTypeNone),
last_gc_type_(collector::kGcTypeNone),
next_gc_type_(collector::kGcTypePartial),
@@ -190,7 +190,6 @@
// If we aren't the zygote, switch to the default non zygote allocator. This may update the
// entrypoints.
if (!Runtime::Current()->IsZygote()) {
- large_object_threshold_ = kDefaultLargeObjectThreshold;
// Background compaction is currently not supported for command line runs.
if (background_collector_type_ != foreground_collector_type_) {
VLOG(heap) << "Disabling background compaction for non zygote";
@@ -468,7 +467,7 @@
// After the zygote we want this to be false if we don't have background compaction enabled so
// that getting primitive array elements is faster.
// We never have homogeneous compaction with GSS and don't need a space with movable objects.
- can_move_objects = !have_zygote_space_ && foreground_collector_type_ != kCollectorTypeGSS;
+ can_move_objects = !HasZygoteSpace() && foreground_collector_type_ != kCollectorTypeGSS;
}
if (collector::SemiSpace::kUseRememberedSet && main_space_ != nullptr) {
RemoveRememberedSet(main_space_);
@@ -801,6 +800,9 @@
os << "Mean allocation time: " << PrettyDuration(allocation_time / total_objects_allocated)
<< "\n";
}
+ if (HasZygoteSpace()) {
+ os << "Zygote space size " << PrettySize(zygote_space_->Size()) << "\n";
+ }
os << "Total mutator paused time: " << PrettyDuration(total_paused_time) << "\n";
os << "Total time waiting for GC to complete: " << PrettyDuration(total_wait_time_) << "\n";
os << "Approximate GC data structures memory overhead: " << gc_memory_overhead_.LoadRelaxed();
@@ -1823,7 +1825,8 @@
Thread* self = Thread::Current();
MutexLock mu(self, zygote_creation_lock_);
// Try to see if we have any Zygote spaces.
- if (have_zygote_space_) {
+ if (HasZygoteSpace()) {
+ LOG(WARNING) << __FUNCTION__ << " called when we already have a zygote space.";
return;
}
VLOG(heap) << "Starting PreZygoteFork";
@@ -1897,26 +1900,26 @@
// from this point on.
RemoveRememberedSet(old_alloc_space);
}
- space::ZygoteSpace* zygote_space = old_alloc_space->CreateZygoteSpace("alloc space",
- low_memory_mode_,
- &non_moving_space_);
+ zygote_space_ = old_alloc_space->CreateZygoteSpace("alloc space", low_memory_mode_,
+ &non_moving_space_);
CHECK(!non_moving_space_->CanMoveObjects());
if (same_space) {
main_space_ = non_moving_space_;
SetSpaceAsDefault(main_space_);
}
delete old_alloc_space;
- CHECK(zygote_space != nullptr) << "Failed creating zygote space";
- AddSpace(zygote_space);
+ CHECK(HasZygoteSpace()) << "Failed creating zygote space";
+ AddSpace(zygote_space_);
non_moving_space_->SetFootprintLimit(non_moving_space_->Capacity());
AddSpace(non_moving_space_);
- have_zygote_space_ = true;
- // Enable large object space allocations.
- large_object_threshold_ = kDefaultLargeObjectThreshold;
// Create the zygote space mod union table.
accounting::ModUnionTable* mod_union_table =
- new accounting::ModUnionTableCardCache("zygote space mod-union table", this, zygote_space);
+ new accounting::ModUnionTableCardCache("zygote space mod-union table", this,
+ zygote_space_);
CHECK(mod_union_table != nullptr) << "Failed to create zygote space mod-union table";
+ // Set all the cards in the mod-union table since we don't know which objects contain references
+ // to large objects.
+ mod_union_table->SetCards();
AddModUnionTable(mod_union_table);
if (collector::SemiSpace::kUseRememberedSet) {
// Add a new remembered set for the post-zygote non-moving space.
@@ -1986,7 +1989,7 @@
// If the heap can't run the GC, silently fail and return that no GC was run.
switch (gc_type) {
case collector::kGcTypePartial: {
- if (!have_zygote_space_) {
+ if (!HasZygoteSpace()) {
return collector::kGcTypeNone;
}
break;
@@ -2810,7 +2813,7 @@
next_gc_type_ = collector::kGcTypeSticky;
} else {
collector::GcType non_sticky_gc_type =
- have_zygote_space_ ? collector::kGcTypePartial : collector::kGcTypeFull;
+ HasZygoteSpace() ? collector::kGcTypePartial : collector::kGcTypeFull;
// Find what the next non sticky collector will be.
collector::GarbageCollector* non_sticky_collector = FindCollectorByGcType(non_sticky_gc_type);
// If the throughput of the current sticky GC >= throughput of the non sticky collector, then
@@ -3033,7 +3036,7 @@
size_t new_native_bytes_allocated = native_bytes_allocated_.FetchAndAddSequentiallyConsistent(bytes);
new_native_bytes_allocated += bytes;
if (new_native_bytes_allocated > native_footprint_gc_watermark_) {
- collector::GcType gc_type = have_zygote_space_ ? collector::kGcTypePartial :
+ collector::GcType gc_type = HasZygoteSpace() ? collector::kGcTypePartial :
collector::kGcTypeFull;
// The second watermark is higher than the gc watermark. If you hit this it means you are
diff --git a/runtime/gc/heap.h b/runtime/gc/heap.h
index d5b49d8..ed93ad9 100644
--- a/runtime/gc/heap.h
+++ b/runtime/gc/heap.h
@@ -79,6 +79,7 @@
namespace space {
class AllocSpace;
class BumpPointerSpace;
+ class ContinuousMemMapAllocSpace;
class DiscontinuousSpace;
class DlMallocSpace;
class ImageSpace;
@@ -87,7 +88,7 @@
class RosAllocSpace;
class Space;
class SpaceTest;
- class ContinuousMemMapAllocSpace;
+ class ZygoteSpace;
} // namespace space
class AgeCardVisitor {
@@ -599,6 +600,10 @@
return &reference_processor_;
}
+ bool HasZygoteSpace() const {
+ return zygote_space_ != nullptr;
+ }
+
private:
// Compact source space to target space.
void Compact(space::ContinuousMemMapAllocSpace* target_space,
@@ -849,8 +854,9 @@
// Lock which guards zygote space creation.
Mutex zygote_creation_lock_;
- // If we have a zygote space.
- bool have_zygote_space_;
+ // Non-null iff we have a zygote space. Doesn't contain the large objects allocated before
+ // zygote space creation.
+ space::ZygoteSpace* zygote_space_;
// Minimum allocation size of large object.
size_t large_object_threshold_;
diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc
index 7d9922d..50dfe21 100644
--- a/runtime/oat_file.cc
+++ b/runtime/oat_file.cc
@@ -534,7 +534,9 @@
methods_pointer_index = num_set_bits;
}
const OatMethodOffsets& oat_method_offsets = methods_pointer_[methods_pointer_index];
- if (oat_file_->IsExecutable() || Runtime::Current()->IsCompiler()) {
+ if (oat_file_->IsExecutable()
+ || (Runtime::Current() == nullptr)
+ || Runtime::Current()->IsCompiler()) {
return OatMethod(
oat_file_->Begin(),
oat_method_offsets.code_offset_,