diff options
| author | 2016-04-15 17:30:05 +0000 | |
|---|---|---|
| committer | 2016-04-15 17:30:05 +0000 | |
| commit | 05241f4edbf6960aac7c04b0b98d05f16a23962b (patch) | |
| tree | 7b02580b8833e8411f061b6a162a58ecffd6ceaf /compiler/optimizing | |
| parent | 6233bff5bd04bb6030929ed6f55e34dde09aa8f3 (diff) | |
| parent | 062157f4e07b525728fa58f4ec57ffe1bf15d545 (diff) | |
Merge "Enable allocation elimination as part of LSE"
Diffstat (limited to 'compiler/optimizing')
| -rw-r--r-- | compiler/optimizing/instruction_builder.cc | 8 | ||||
| -rw-r--r-- | compiler/optimizing/load_store_elimination.cc | 23 | ||||
| -rw-r--r-- | compiler/optimizing/nodes.h | 17 |
3 files changed, 25 insertions, 23 deletions
diff --git a/compiler/optimizing/instruction_builder.cc b/compiler/optimizing/instruction_builder.cc index f5e49c2235..12cb826395 100644 --- a/compiler/optimizing/instruction_builder.cc +++ b/compiler/optimizing/instruction_builder.cc @@ -897,12 +897,12 @@ bool HInstructionBuilder::BuildNewInstance(uint16_t type_index, uint32_t dex_pc) Handle<mirror::DexCache> outer_dex_cache = outer_compilation_unit_->GetDexCache(); bool finalizable; - bool can_throw = NeedsAccessCheck(type_index, dex_cache, &finalizable); + bool needs_access_check = NeedsAccessCheck(type_index, dex_cache, &finalizable); // Only the non-resolved entrypoint handles the finalizable class case. If we // need access checks, then we haven't resolved the method and the class may // again be finalizable. - QuickEntrypointEnum entrypoint = (finalizable || can_throw) + QuickEntrypointEnum entrypoint = (finalizable || needs_access_check) ? kQuickAllocObject : kQuickAllocObjectInitialized; @@ -917,7 +917,7 @@ bool HInstructionBuilder::BuildNewInstance(uint16_t type_index, uint32_t dex_pc) outer_dex_file, IsOutermostCompilingClass(type_index), dex_pc, - /*needs_access_check*/ can_throw, + needs_access_check, compiler_driver_->CanAssumeTypeIsPresentInDexCache(outer_dex_cache, type_index)); AppendInstruction(load_class); @@ -933,7 +933,7 @@ bool HInstructionBuilder::BuildNewInstance(uint16_t type_index, uint32_t dex_pc) dex_pc, type_index, *dex_compilation_unit_->GetDexFile(), - can_throw, + needs_access_check, finalizable, entrypoint)); return true; diff --git a/compiler/optimizing/load_store_elimination.cc b/compiler/optimizing/load_store_elimination.cc index e1977b1798..ac7ed86d1d 100644 --- a/compiler/optimizing/load_store_elimination.cc +++ b/compiler/optimizing/load_store_elimination.cc @@ -480,7 +480,7 @@ class HeapLocationCollector : public HGraphVisitor { // alias analysis and won't be as effective. bool has_volatile_; // If there are volatile field accesses. bool has_monitor_operations_; // If there are monitor operations. - bool may_deoptimize_; + bool may_deoptimize_; // Only true for HDeoptimize with single-frame deoptimization. DISALLOW_COPY_AND_ASSIGN(HeapLocationCollector); }; @@ -551,19 +551,20 @@ class LSEVisitor : public HGraphVisitor { } // At this point, stores in possibly_removed_stores_ can be safely removed. - size = possibly_removed_stores_.size(); - for (size_t i = 0; i < size; i++) { + for (size_t i = 0, e = possibly_removed_stores_.size(); i < e; i++) { HInstruction* store = possibly_removed_stores_[i]; DCHECK(store->IsInstanceFieldSet() || store->IsStaticFieldSet() || store->IsArraySet()); store->GetBlock()->RemoveInstruction(store); } - // TODO: remove unnecessary allocations. - // Eliminate instructions in singleton_new_instances_ that: - // - don't have uses, - // - don't have finalizers, - // - are instantiable and accessible, - // - have no/separate clinit check. + // Eliminate allocations that are not used. + for (size_t i = 0, e = singleton_new_instances_.size(); i < e; i++) { + HInstruction* new_instance = singleton_new_instances_[i]; + if (!new_instance->HasNonEnvironmentUses()) { + new_instance->RemoveEnvironmentUsers(); + new_instance->GetBlock()->RemoveInstruction(new_instance); + } + } } private: @@ -969,8 +970,8 @@ class LSEVisitor : public HGraphVisitor { if (!heap_location_collector_.MayDeoptimize() && ref_info->IsSingletonAndNotReturned() && !new_instance->IsFinalizable() && - !new_instance->CanThrow()) { - // TODO: add new_instance to singleton_new_instances_ and enable allocation elimination. + !new_instance->NeedsAccessCheck()) { + singleton_new_instances_.push_back(new_instance); } ArenaVector<HInstruction*>& heap_values = heap_values_for_[new_instance->GetBlock()->GetBlockId()]; diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h index dc5a8fa9cb..69f0b514f9 100644 --- a/compiler/optimizing/nodes.h +++ b/compiler/optimizing/nodes.h @@ -3652,14 +3652,14 @@ class HNewInstance : public HExpression<2> { uint32_t dex_pc, uint16_t type_index, const DexFile& dex_file, - bool can_throw, + bool needs_access_check, bool finalizable, QuickEntrypointEnum entrypoint) : HExpression(Primitive::kPrimNot, SideEffects::CanTriggerGC(), dex_pc), type_index_(type_index), dex_file_(dex_file), entrypoint_(entrypoint) { - SetPackedFlag<kFlagCanThrow>(can_throw); + SetPackedFlag<kFlagNeedsAccessCheck>(needs_access_check); SetPackedFlag<kFlagFinalizable>(finalizable); SetRawInputAt(0, cls); SetRawInputAt(1, current_method); @@ -3671,10 +3671,11 @@ class HNewInstance : public HExpression<2> { // Calls runtime so needs an environment. bool NeedsEnvironment() const OVERRIDE { return true; } - // It may throw when called on type that's not instantiable/accessible. - // It can throw OOME. - // TODO: distinguish between the two cases so we can for example allow allocation elimination. - bool CanThrow() const OVERRIDE { return GetPackedFlag<kFlagCanThrow>() || true; } + // Can throw errors when out-of-memory or if it's not instantiable/accessible. + bool CanThrow() const OVERRIDE { return true; } + + // Needs to call into runtime to make sure it's instantiable/accessible. + bool NeedsAccessCheck() const { return GetPackedFlag<kFlagNeedsAccessCheck>(); } bool IsFinalizable() const { return GetPackedFlag<kFlagFinalizable>(); } @@ -3691,8 +3692,8 @@ class HNewInstance : public HExpression<2> { DECLARE_INSTRUCTION(NewInstance); private: - static constexpr size_t kFlagCanThrow = kNumberOfExpressionPackedBits; - static constexpr size_t kFlagFinalizable = kFlagCanThrow + 1; + static constexpr size_t kFlagNeedsAccessCheck = kNumberOfExpressionPackedBits; + static constexpr size_t kFlagFinalizable = kFlagNeedsAccessCheck + 1; static constexpr size_t kNumberOfNewInstancePackedBits = kFlagFinalizable + 1; static_assert(kNumberOfNewInstancePackedBits <= kMaxNumberOfPackedBits, "Too many packed fields."); |