Revert "Revert "Refactor HGraphBuilder and SsaBuilder to remove HLocals""
This patch merges the instruction-building phases from HGraphBuilder
and SsaBuilder into a single HInstructionBuilder class. As a result,
it is not necessary to generate HLocal, HLoadLocal and HStoreLocal
instructions any more, as the builder produces SSA form directly.
Saves 5-15% of arena-allocated memory (see bug for more data):
GMS 20.46MB => 19.26MB (-5.86%)
Maps 24.12MB => 21.47MB (-10.98%)
YouTube 28.60MB => 26.01MB (-9.05%)
This CL fixed an issue with parsing quickened instructions.
Bug: 27894376
Bug: 27998571
Bug: 27995065
Change-Id: I20dbe1bf2d0fe296377478db98cb86cba695e694
diff --git a/compiler/optimizing/ssa_builder.cc b/compiler/optimizing/ssa_builder.cc
index 5a05256..eeadbeb 100644
--- a/compiler/optimizing/ssa_builder.cc
+++ b/compiler/optimizing/ssa_builder.cc
@@ -23,30 +23,9 @@
namespace art {
-void SsaBuilder::SetLoopHeaderPhiInputs() {
- for (size_t i = loop_headers_.size(); i > 0; --i) {
- HBasicBlock* block = loop_headers_[i - 1];
- for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
- HPhi* phi = it.Current()->AsPhi();
- size_t vreg = phi->GetRegNumber();
- for (HBasicBlock* predecessor : block->GetPredecessors()) {
- HInstruction* value = ValueOfLocal(predecessor, vreg);
- if (value == nullptr) {
- // Vreg is undefined at this predecessor. Mark it dead and leave with
- // fewer inputs than predecessors. SsaChecker will fail if not removed.
- phi->SetDead();
- break;
- } else {
- phi->AddInput(value);
- }
- }
- }
- }
-}
-
void SsaBuilder::FixNullConstantType() {
// The order doesn't matter here.
- for (HReversePostOrderIterator itb(*GetGraph()); !itb.Done(); itb.Advance()) {
+ for (HReversePostOrderIterator itb(*graph_); !itb.Done(); itb.Advance()) {
for (HInstructionIterator it(itb.Current()->GetInstructions()); !it.Done(); it.Advance()) {
HInstruction* equality_instr = it.Current();
if (!equality_instr->IsEqual() && !equality_instr->IsNotEqual()) {
@@ -71,14 +50,14 @@
// can only be the 0 constant.
DCHECK(int_operand->IsIntConstant()) << int_operand->DebugName();
DCHECK_EQ(0, int_operand->AsIntConstant()->GetValue());
- equality_instr->ReplaceInput(GetGraph()->GetNullConstant(), int_operand == right ? 1 : 0);
+ equality_instr->ReplaceInput(graph_->GetNullConstant(), int_operand == right ? 1 : 0);
}
}
}
void SsaBuilder::EquivalentPhisCleanup() {
// The order doesn't matter here.
- for (HReversePostOrderIterator itb(*GetGraph()); !itb.Done(); itb.Advance()) {
+ for (HReversePostOrderIterator itb(*graph_); !itb.Done(); itb.Advance()) {
for (HInstructionIterator it(itb.Current()->GetPhis()); !it.Done(); it.Advance()) {
HPhi* phi = it.Current()->AsPhi();
HPhi* next = phi->GetNextEquivalentPhiWithSameType();
@@ -100,7 +79,7 @@
}
void SsaBuilder::FixEnvironmentPhis() {
- for (HReversePostOrderIterator it(*GetGraph()); !it.Done(); it.Advance()) {
+ for (HReversePostOrderIterator it(*graph_); !it.Done(); it.Advance()) {
HBasicBlock* block = it.Current();
for (HInstructionIterator it_phis(block->GetPhis()); !it_phis.Done(); it_phis.Advance()) {
HPhi* phi = it_phis.Current()->AsPhi();
@@ -254,9 +233,9 @@
}
void SsaBuilder::RunPrimitiveTypePropagation() {
- ArenaVector<HPhi*> worklist(GetGraph()->GetArena()->Adapter());
+ ArenaVector<HPhi*> worklist(graph_->GetArena()->Adapter());
- for (HReversePostOrderIterator it(*GetGraph()); !it.Done(); it.Advance()) {
+ for (HReversePostOrderIterator it(*graph_); !it.Done(); it.Advance()) {
HBasicBlock* block = it.Current();
if (block->IsLoopHeader()) {
for (HInstructionIterator phi_it(block->GetPhis()); !phi_it.Done(); phi_it.Advance()) {
@@ -300,8 +279,14 @@
static HArrayGet* FindFloatOrDoubleEquivalentOfArrayGet(HArrayGet* aget) {
Primitive::Type type = aget->GetType();
DCHECK(Primitive::IsIntOrLongType(type));
- HArrayGet* next = aget->GetNext()->AsArrayGet();
- return (next != nullptr && next->IsEquivalentOf(aget)) ? next : nullptr;
+ HInstruction* next = aget->GetNext();
+ if (next != nullptr && next->IsArrayGet()) {
+ HArrayGet* next_aget = next->AsArrayGet();
+ if (next_aget->IsEquivalentOf(aget)) {
+ return next_aget;
+ }
+ }
+ return nullptr;
}
static HArrayGet* CreateFloatOrDoubleEquivalentOfArrayGet(HArrayGet* aget) {
@@ -334,7 +319,7 @@
// uses (because they are untyped) and environment uses (if --debuggable).
// After resolving all ambiguous ArrayGets, we will re-run primitive type
// propagation on the Phis which need to be updated.
- ArenaVector<HPhi*> worklist(GetGraph()->GetArena()->Adapter());
+ ArenaVector<HPhi*> worklist(graph_->GetArena()->Adapter());
{
ScopedObjectAccess soa(Thread::Current());
@@ -452,7 +437,7 @@
}
void SsaBuilder::RemoveRedundantUninitializedStrings() {
- if (GetGraph()->IsDebuggable()) {
+ if (graph_->IsDebuggable()) {
// Do not perform the optimization for consistency with the interpreter
// which always allocates an object for new-instance of String.
return;
@@ -460,11 +445,13 @@
for (HNewInstance* new_instance : uninitialized_strings_) {
DCHECK(new_instance->IsInBlock());
+ DCHECK(new_instance->IsStringAlloc());
+
// Replace NewInstance of String with NullConstant if not used prior to
// calling StringFactory. In case of deoptimization, the interpreter is
// expected to skip null check on the `this` argument of the StringFactory call.
if (!new_instance->HasNonEnvironmentUses() && !HasAliasInEnvironments(new_instance)) {
- new_instance->ReplaceWith(GetGraph()->GetNullConstant());
+ new_instance->ReplaceWith(graph_->GetNullConstant());
new_instance->GetBlock()->RemoveInstruction(new_instance);
// Remove LoadClass if not needed any more.
@@ -495,57 +482,47 @@
}
GraphAnalysisResult SsaBuilder::BuildSsa() {
- DCHECK(!GetGraph()->IsInSsaForm());
+ DCHECK(!graph_->IsInSsaForm());
- // 1) Visit in reverse post order. We need to have all predecessors of a block
- // visited (with the exception of loops) in order to create the right environment
- // for that block. For loops, we create phis whose inputs will be set in 2).
- for (HReversePostOrderIterator it(*GetGraph()); !it.Done(); it.Advance()) {
- VisitBasicBlock(it.Current());
- }
-
- // 2) Set inputs of loop header phis.
- SetLoopHeaderPhiInputs();
-
- // 3) Propagate types of phis. At this point, phis are typed void in the general
+ // 1) Propagate types of phis. At this point, phis are typed void in the general
// case, or float/double/reference if we created an equivalent phi. So we need
// to propagate the types across phis to give them a correct type. If a type
// conflict is detected in this stage, the phi is marked dead.
RunPrimitiveTypePropagation();
- // 4) Now that the correct primitive types have been assigned, we can get rid
+ // 2) Now that the correct primitive types have been assigned, we can get rid
// of redundant phis. Note that we cannot do this phase before type propagation,
// otherwise we could get rid of phi equivalents, whose presence is a requirement
// for the type propagation phase. Note that this is to satisfy statement (a)
// of the SsaBuilder (see ssa_builder.h).
- SsaRedundantPhiElimination(GetGraph()).Run();
+ SsaRedundantPhiElimination(graph_).Run();
- // 5) Fix the type for null constants which are part of an equality comparison.
+ // 3) Fix the type for null constants which are part of an equality comparison.
// We need to do this after redundant phi elimination, to ensure the only cases
// that we can see are reference comparison against 0. The redundant phi
// elimination ensures we do not see a phi taking two 0 constants in a HEqual
// or HNotEqual.
FixNullConstantType();
- // 6) Compute type of reference type instructions. The pass assumes that
+ // 4) Compute type of reference type instructions. The pass assumes that
// NullConstant has been fixed up.
- ReferenceTypePropagation(GetGraph(), handles_, /* is_first_run */ true).Run();
+ ReferenceTypePropagation(graph_, handles_, /* is_first_run */ true).Run();
- // 7) Step 1) duplicated ArrayGet instructions with ambiguous type (int/float
- // or long/double) and marked ArraySets with ambiguous input type. Now that RTP
- // computed the type of the array input, the ambiguity can be resolved and the
- // correct equivalents kept.
+ // 5) HInstructionBuilder duplicated ArrayGet instructions with ambiguous type
+ // (int/float or long/double) and marked ArraySets with ambiguous input type.
+ // Now that RTP computed the type of the array input, the ambiguity can be
+ // resolved and the correct equivalents kept.
if (!FixAmbiguousArrayOps()) {
return kAnalysisFailAmbiguousArrayOp;
}
- // 8) Mark dead phis. This will mark phis which are not used by instructions
+ // 6) Mark dead phis. This will mark phis which are not used by instructions
// or other live phis. If compiling as debuggable code, phis will also be kept
// live if they have an environment use.
- SsaDeadPhiElimination dead_phi_elimimation(GetGraph());
+ SsaDeadPhiElimination dead_phi_elimimation(graph_);
dead_phi_elimimation.MarkDeadPhis();
- // 9) Make sure environments use the right phi equivalent: a phi marked dead
+ // 7) Make sure environments use the right phi equivalent: a phi marked dead
// can have a phi equivalent that is not dead. In that case we have to replace
// it with the live equivalent because deoptimization and try/catch rely on
// environments containing values of all live vregs at that point. Note that
@@ -554,165 +531,26 @@
// environments to just reference one.
FixEnvironmentPhis();
- // 10) Now that the right phis are used for the environments, we can eliminate
+ // 8) Now that the right phis are used for the environments, we can eliminate
// phis we do not need. Regardless of the debuggable status, this phase is
/// necessary for statement (b) of the SsaBuilder (see ssa_builder.h), as well
// as for the code generation, which does not deal with phis of conflicting
// input types.
dead_phi_elimimation.EliminateDeadPhis();
- // 11) Step 1) replaced uses of NewInstances of String with the results of
- // their corresponding StringFactory calls. Unless the String objects are used
- // before they are initialized, they can be replaced with NullConstant.
- // Note that this optimization is valid only if unsimplified code does not use
- // the uninitialized value because we assume execution can be deoptimized at
- // any safepoint. We must therefore perform it before any other optimizations.
+ // 9) HInstructionBuidler replaced uses of NewInstances of String with the
+ // results of their corresponding StringFactory calls. Unless the String
+ // objects are used before they are initialized, they can be replaced with
+ // NullConstant. Note that this optimization is valid only if unsimplified
+ // code does not use the uninitialized value because we assume execution can
+ // be deoptimized at any safepoint. We must therefore perform it before any
+ // other optimizations.
RemoveRedundantUninitializedStrings();
- // 12) Clear locals.
- for (HInstructionIterator it(GetGraph()->GetEntryBlock()->GetInstructions());
- !it.Done();
- it.Advance()) {
- HInstruction* current = it.Current();
- if (current->IsLocal()) {
- current->GetBlock()->RemoveInstruction(current);
- }
- }
-
- GetGraph()->SetInSsaForm();
+ graph_->SetInSsaForm();
return kAnalysisSuccess;
}
-ArenaVector<HInstruction*>* SsaBuilder::GetLocalsFor(HBasicBlock* block) {
- ArenaVector<HInstruction*>* locals = &locals_for_[block->GetBlockId()];
- const size_t vregs = GetGraph()->GetNumberOfVRegs();
- if (locals->empty() && vregs != 0u) {
- locals->resize(vregs, nullptr);
-
- if (block->IsCatchBlock()) {
- ArenaAllocator* arena = GetGraph()->GetArena();
- // We record incoming inputs of catch phis at throwing instructions and
- // must therefore eagerly create the phis. Phis for undefined vregs will
- // be deleted when the first throwing instruction with the vreg undefined
- // is encountered. Unused phis will be removed by dead phi analysis.
- for (size_t i = 0; i < vregs; ++i) {
- // No point in creating the catch phi if it is already undefined at
- // the first throwing instruction.
- HInstruction* current_local_value = (*current_locals_)[i];
- if (current_local_value != nullptr) {
- HPhi* phi = new (arena) HPhi(
- arena,
- i,
- 0,
- current_local_value->GetType());
- block->AddPhi(phi);
- (*locals)[i] = phi;
- }
- }
- }
- }
- return locals;
-}
-
-HInstruction* SsaBuilder::ValueOfLocal(HBasicBlock* block, size_t local) {
- ArenaVector<HInstruction*>* locals = GetLocalsFor(block);
- return (*locals)[local];
-}
-
-void SsaBuilder::VisitBasicBlock(HBasicBlock* block) {
- current_locals_ = GetLocalsFor(block);
-
- if (block->IsCatchBlock()) {
- // Catch phis were already created and inputs collected from throwing sites.
- if (kIsDebugBuild) {
- // Make sure there was at least one throwing instruction which initialized
- // locals (guaranteed by HGraphBuilder) and that all try blocks have been
- // visited already (from HTryBoundary scoping and reverse post order).
- bool catch_block_visited = false;
- for (HReversePostOrderIterator it(*GetGraph()); !it.Done(); it.Advance()) {
- HBasicBlock* current = it.Current();
- if (current == block) {
- catch_block_visited = true;
- } else if (current->IsTryBlock() &&
- current->GetTryCatchInformation()->GetTryEntry().HasExceptionHandler(*block)) {
- DCHECK(!catch_block_visited) << "Catch block visited before its try block.";
- }
- }
- DCHECK_EQ(current_locals_->size(), GetGraph()->GetNumberOfVRegs())
- << "No instructions throwing into a live catch block.";
- }
- } else if (block->IsLoopHeader()) {
- // If the block is a loop header, we know we only have visited the pre header
- // because we are visiting in reverse post order. We create phis for all initialized
- // locals from the pre header. Their inputs will be populated at the end of
- // the analysis.
- for (size_t local = 0; local < current_locals_->size(); ++local) {
- HInstruction* incoming = ValueOfLocal(block->GetLoopInformation()->GetPreHeader(), local);
- if (incoming != nullptr) {
- HPhi* phi = new (GetGraph()->GetArena()) HPhi(
- GetGraph()->GetArena(),
- local,
- 0,
- incoming->GetType());
- block->AddPhi(phi);
- (*current_locals_)[local] = phi;
- }
- }
- // Save the loop header so that the last phase of the analysis knows which
- // blocks need to be updated.
- loop_headers_.push_back(block);
- } else if (block->GetPredecessors().size() > 0) {
- // All predecessors have already been visited because we are visiting in reverse post order.
- // We merge the values of all locals, creating phis if those values differ.
- for (size_t local = 0; local < current_locals_->size(); ++local) {
- bool one_predecessor_has_no_value = false;
- bool is_different = false;
- HInstruction* value = ValueOfLocal(block->GetPredecessors()[0], local);
-
- for (HBasicBlock* predecessor : block->GetPredecessors()) {
- HInstruction* current = ValueOfLocal(predecessor, local);
- if (current == nullptr) {
- one_predecessor_has_no_value = true;
- break;
- } else if (current != value) {
- is_different = true;
- }
- }
-
- if (one_predecessor_has_no_value) {
- // If one predecessor has no value for this local, we trust the verifier has
- // successfully checked that there is a store dominating any read after this block.
- continue;
- }
-
- if (is_different) {
- HInstruction* first_input = ValueOfLocal(block->GetPredecessors()[0], local);
- HPhi* phi = new (GetGraph()->GetArena()) HPhi(
- GetGraph()->GetArena(),
- local,
- block->GetPredecessors().size(),
- first_input->GetType());
- for (size_t i = 0; i < block->GetPredecessors().size(); i++) {
- HInstruction* pred_value = ValueOfLocal(block->GetPredecessors()[i], local);
- phi->SetRawInputAt(i, pred_value);
- }
- block->AddPhi(phi);
- value = phi;
- }
- (*current_locals_)[local] = value;
- }
- }
-
- // Visit all instructions. The instructions of interest are:
- // - HLoadLocal: replace them with the current value of the local.
- // - HStoreLocal: update current value of the local and remove the instruction.
- // - Instructions that require an environment: populate their environment
- // with the current values of the locals.
- for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
- it.Current()->Accept(this);
- }
-}
-
/**
* Constants in the Dex format are not typed. So the builder types them as
* integers, but when doing the SSA form, we might realize the constant
@@ -723,11 +561,10 @@
// We place the floating point constant next to this constant.
HFloatConstant* result = constant->GetNext()->AsFloatConstant();
if (result == nullptr) {
- HGraph* graph = constant->GetBlock()->GetGraph();
- ArenaAllocator* allocator = graph->GetArena();
- result = new (allocator) HFloatConstant(bit_cast<float, int32_t>(constant->GetValue()));
+ float value = bit_cast<float, int32_t>(constant->GetValue());
+ result = new (graph_->GetArena()) HFloatConstant(value);
constant->GetBlock()->InsertInstructionBefore(result, constant->GetNext());
- graph->CacheFloatConstant(result);
+ graph_->CacheFloatConstant(result);
} else {
// If there is already a constant with the expected type, we know it is
// the floating point equivalent of this constant.
@@ -746,11 +583,10 @@
// We place the floating point constant next to this constant.
HDoubleConstant* result = constant->GetNext()->AsDoubleConstant();
if (result == nullptr) {
- HGraph* graph = constant->GetBlock()->GetGraph();
- ArenaAllocator* allocator = graph->GetArena();
- result = new (allocator) HDoubleConstant(bit_cast<double, int64_t>(constant->GetValue()));
+ double value = bit_cast<double, int64_t>(constant->GetValue());
+ result = new (graph_->GetArena()) HDoubleConstant(value);
constant->GetBlock()->InsertInstructionBefore(result, constant->GetNext());
- graph->CacheDoubleConstant(result);
+ graph_->CacheDoubleConstant(result);
} else {
// If there is already a constant with the expected type, we know it is
// the floating point equivalent of this constant.
@@ -781,7 +617,7 @@
if (next == nullptr
|| (next->AsPhi()->GetRegNumber() != phi->GetRegNumber())
|| (next->GetType() != type)) {
- ArenaAllocator* allocator = phi->GetBlock()->GetGraph()->GetArena();
+ ArenaAllocator* allocator = graph_->GetArena();
HPhi* new_phi = new (allocator) HPhi(allocator, phi->GetRegNumber(), phi->InputCount(), type);
for (size_t i = 0, e = phi->InputCount(); i < e; ++i) {
// Copy the inputs. Note that the graph may not be correctly typed
@@ -841,7 +677,7 @@
HInstruction* SsaBuilder::GetReferenceTypeEquivalent(HInstruction* value) {
if (value->IsIntConstant() && value->AsIntConstant()->GetValue() == 0) {
- return value->GetBlock()->GetGraph()->GetNullConstant();
+ return graph_->GetNullConstant();
} else if (value->IsPhi()) {
return GetFloatDoubleOrReferenceEquivalentOfPhi(value->AsPhi(), Primitive::kPrimNot);
} else {
@@ -849,171 +685,4 @@
}
}
-void SsaBuilder::VisitLoadLocal(HLoadLocal* load) {
- Primitive::Type load_type = load->GetType();
- HInstruction* value = (*current_locals_)[load->GetLocal()->GetRegNumber()];
- // If the operation requests a specific type, we make sure its input is of that type.
- if (load_type != value->GetType()) {
- if (load_type == Primitive::kPrimFloat || load_type == Primitive::kPrimDouble) {
- value = GetFloatOrDoubleEquivalent(value, load_type);
- } else if (load_type == Primitive::kPrimNot) {
- value = GetReferenceTypeEquivalent(value);
- }
- }
-
- load->ReplaceWith(value);
- load->GetBlock()->RemoveInstruction(load);
-}
-
-void SsaBuilder::VisitStoreLocal(HStoreLocal* store) {
- uint32_t reg_number = store->GetLocal()->GetRegNumber();
- HInstruction* stored_value = store->InputAt(1);
- Primitive::Type stored_type = stored_value->GetType();
- DCHECK_NE(stored_type, Primitive::kPrimVoid);
-
- // Storing into vreg `reg_number` may implicitly invalidate the surrounding
- // registers. Consider the following cases:
- // (1) Storing a wide value must overwrite previous values in both `reg_number`
- // and `reg_number+1`. We store `nullptr` in `reg_number+1`.
- // (2) If vreg `reg_number-1` holds a wide value, writing into `reg_number`
- // must invalidate it. We store `nullptr` in `reg_number-1`.
- // Consequently, storing a wide value into the high vreg of another wide value
- // will invalidate both `reg_number-1` and `reg_number+1`.
-
- if (reg_number != 0) {
- HInstruction* local_low = (*current_locals_)[reg_number - 1];
- if (local_low != nullptr && Primitive::Is64BitType(local_low->GetType())) {
- // The vreg we are storing into was previously the high vreg of a pair.
- // We need to invalidate its low vreg.
- DCHECK((*current_locals_)[reg_number] == nullptr);
- (*current_locals_)[reg_number - 1] = nullptr;
- }
- }
-
- (*current_locals_)[reg_number] = stored_value;
- if (Primitive::Is64BitType(stored_type)) {
- // We are storing a pair. Invalidate the instruction in the high vreg.
- (*current_locals_)[reg_number + 1] = nullptr;
- }
-
- store->GetBlock()->RemoveInstruction(store);
-}
-
-bool SsaBuilder::IsFirstAtThrowingDexPc(HInstruction* instruction) const {
- uint32_t dex_pc = instruction->GetDexPc();
- if (dex_pc == kNoDexPc) {
- return false;
- }
-
- // Needs to be the first HInstruction with this dex_pc.
- HInstruction* previous = instruction->GetPrevious();
- if (previous != nullptr && previous->GetDexPc() == dex_pc) {
- return false;
- }
-
- if (instruction->IsControlFlow() && !instruction->IsThrow()) {
- // Special-case non-throwing control-flow HInstruction because artifically
- // created ones are given dex_pc of the nearest bytecode instructions.
- return false;
- }
-
- return IsThrowingDexInstruction(GetDexInstructionAt(code_item_, dex_pc));
-}
-
-void SsaBuilder::VisitInstruction(HInstruction* instruction) {
- if (instruction->NeedsEnvironment()) {
- HEnvironment* environment = new (GetGraph()->GetArena()) HEnvironment(
- GetGraph()->GetArena(),
- current_locals_->size(),
- GetGraph()->GetDexFile(),
- GetGraph()->GetMethodIdx(),
- instruction->GetDexPc(),
- GetGraph()->GetInvokeType(),
- instruction);
- environment->CopyFrom(*current_locals_);
- instruction->SetRawEnvironment(environment);
- }
-
- // If in a try block, propagate values of locals into catch blocks.
- if (instruction->GetBlock()->IsTryBlock() && IsFirstAtThrowingDexPc(instruction)) {
- const HTryBoundary& try_entry =
- instruction->GetBlock()->GetTryCatchInformation()->GetTryEntry();
- for (HBasicBlock* catch_block : try_entry.GetExceptionHandlers()) {
- ArenaVector<HInstruction*>* handler_locals = GetLocalsFor(catch_block);
- DCHECK_EQ(handler_locals->size(), current_locals_->size());
- for (size_t vreg = 0, e = current_locals_->size(); vreg < e; ++vreg) {
- HInstruction* handler_value = (*handler_locals)[vreg];
- if (handler_value == nullptr) {
- // Vreg was undefined at a previously encountered throwing instruction
- // and the catch phi was deleted. Do not record the local value.
- continue;
- }
- DCHECK(handler_value->IsPhi());
-
- HInstruction* local_value = (*current_locals_)[vreg];
- if (local_value == nullptr) {
- // This is the first instruction throwing into `catch_block` where
- // `vreg` is undefined. Delete the catch phi.
- catch_block->RemovePhi(handler_value->AsPhi());
- (*handler_locals)[vreg] = nullptr;
- } else {
- // Vreg has been defined at all instructions throwing into `catch_block`
- // encountered so far. Record the local value in the catch phi.
- handler_value->AsPhi()->AddInput(local_value);
- }
- }
- }
- }
-}
-
-void SsaBuilder::VisitArrayGet(HArrayGet* aget) {
- Primitive::Type type = aget->GetType();
- DCHECK(!Primitive::IsFloatingPointType(type));
- if (Primitive::IsIntOrLongType(type)) {
- ambiguous_agets_.push_back(aget);
- }
- VisitInstruction(aget);
-}
-
-void SsaBuilder::VisitArraySet(HArraySet* aset) {
- Primitive::Type type = aset->GetValue()->GetType();
- if (Primitive::IsIntOrLongType(type)) {
- ambiguous_asets_.push_back(aset);
- }
- VisitInstruction(aset);
-}
-
-void SsaBuilder::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
- VisitInstruction(invoke);
-
- if (invoke->IsStringInit()) {
- // This is a StringFactory call which acts as a String constructor. Its
- // result replaces the empty String pre-allocated by NewInstance.
- HInstruction* arg_this = invoke->GetAndRemoveThisArgumentOfStringInit();
-
- // Replacing the NewInstance might render it redundant. Keep a list of these
- // to be visited once it is clear whether it is has remaining uses.
- if (arg_this->IsNewInstance()) {
- HNewInstance* new_instance = arg_this->AsNewInstance();
- // Note that in some rare cases (b/27847265), the same NewInstance may be seen
- // multiple times. We should only consider it once for removal, so we
- // ensure it is not added more than once.
- if (!ContainsElement(uninitialized_strings_, new_instance)) {
- uninitialized_strings_.push_back(new_instance);
- }
- } else {
- DCHECK(arg_this->IsPhi());
- // NewInstance is not the direct input of the StringFactory call. It might
- // be redundant but optimizing this case is not worth the effort.
- }
-
- // Walk over all vregs and replace any occurrence of `arg_this` with `invoke`.
- for (size_t vreg = 0, e = current_locals_->size(); vreg < e; ++vreg) {
- if ((*current_locals_)[vreg] == arg_this) {
- (*current_locals_)[vreg] = invoke;
- }
- }
- }
-}
-
} // namespace art