Merge "ART: X86Mir2Lir::OpRegRegReg should expect kOpMul for r_dest == r_src2 case"
diff --git a/compiler/compilers.cc b/compiler/compilers.cc
deleted file mode 100644
index 2481128..0000000
--- a/compiler/compilers.cc
+++ /dev/null
@@ -1,159 +0,0 @@
-/*
- * Copyright (C) 2014 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 "compilers.h"
-
-#include "dex/mir_graph.h"
-#include "dex/quick/mir_to_lir.h"
-#include "elf_writer_quick.h"
-#include "mirror/art_method-inl.h"
-
-namespace art {
-
-extern "C" void ArtInitQuickCompilerContext(art::CompilerDriver* driver);
-extern "C" void ArtUnInitQuickCompilerContext(art::CompilerDriver* driver);
-extern "C" art::CompiledMethod* ArtQuickCompileMethod(art::CompilerDriver* driver,
- const art::DexFile::CodeItem* code_item,
- uint32_t access_flags,
- art::InvokeType invoke_type,
- uint16_t class_def_idx,
- uint32_t method_idx,
- jobject class_loader,
- const art::DexFile& dex_file);
-
-extern "C" art::CompiledMethod* ArtQuickJniCompileMethod(art::CompilerDriver* driver,
- uint32_t access_flags, uint32_t method_idx,
- const art::DexFile& dex_file);
-
-// Hack for CFI CIE initialization
-extern std::vector<uint8_t>* X86CFIInitialization(bool is_x86_64);
-
-void QuickCompiler::Init() const {
- ArtInitQuickCompilerContext(GetCompilerDriver());
-}
-
-void QuickCompiler::UnInit() const {
- ArtUnInitQuickCompilerContext(GetCompilerDriver());
-}
-
-CompiledMethod* QuickCompiler::Compile(const DexFile::CodeItem* code_item,
- uint32_t access_flags,
- InvokeType invoke_type,
- uint16_t class_def_idx,
- uint32_t method_idx,
- jobject class_loader,
- const DexFile& dex_file) const {
- CompiledMethod* method = TryCompileWithSeaIR(code_item,
- access_flags,
- invoke_type,
- class_def_idx,
- method_idx,
- class_loader,
- dex_file);
- if (method != nullptr) {
- return method;
- }
-
- return ArtQuickCompileMethod(GetCompilerDriver(),
- code_item,
- access_flags,
- invoke_type,
- class_def_idx,
- method_idx,
- class_loader,
- dex_file);
-}
-
-CompiledMethod* QuickCompiler::JniCompile(uint32_t access_flags,
- uint32_t method_idx,
- const DexFile& dex_file) const {
- return ArtQuickJniCompileMethod(GetCompilerDriver(), access_flags, method_idx, dex_file);
-}
-
-uintptr_t QuickCompiler::GetEntryPointOf(mirror::ArtMethod* method) const {
- size_t pointer_size = InstructionSetPointerSize(GetCompilerDriver()->GetInstructionSet());
- return reinterpret_cast<uintptr_t>(method->GetEntryPointFromQuickCompiledCodePtrSize(
- pointer_size));
-}
-
-bool QuickCompiler::WriteElf(art::File* file,
- OatWriter* oat_writer,
- const std::vector<const art::DexFile*>& dex_files,
- const std::string& android_root,
- bool is_host) const {
- return art::ElfWriterQuick::Create(file, oat_writer, dex_files, android_root, is_host,
- *GetCompilerDriver());
-}
-
-Backend* QuickCompiler::GetCodeGenerator(CompilationUnit* cu, void* compilation_unit) const {
- Mir2Lir* mir_to_lir = nullptr;
- switch (cu->instruction_set) {
- case kThumb2:
- mir_to_lir = ArmCodeGenerator(cu, cu->mir_graph.get(), &cu->arena);
- break;
- case kArm64:
- mir_to_lir = Arm64CodeGenerator(cu, cu->mir_graph.get(), &cu->arena);
- break;
- case kMips:
- mir_to_lir = MipsCodeGenerator(cu, cu->mir_graph.get(), &cu->arena);
- break;
- case kX86:
- // Fall-through.
- case kX86_64:
- mir_to_lir = X86CodeGenerator(cu, cu->mir_graph.get(), &cu->arena);
- break;
- default:
- LOG(FATAL) << "Unexpected instruction set: " << cu->instruction_set;
- }
-
- /* The number of compiler temporaries depends on backend so set it up now if possible */
- if (mir_to_lir) {
- size_t max_temps = mir_to_lir->GetMaxPossibleCompilerTemps();
- bool set_max = cu->mir_graph->SetMaxAvailableNonSpecialCompilerTemps(max_temps);
- CHECK(set_max);
- }
- return mir_to_lir;
-}
-
-std::vector<uint8_t>* QuickCompiler::GetCallFrameInformationInitialization(
- const CompilerDriver& driver) const {
- if (driver.GetInstructionSet() == kX86) {
- return X86CFIInitialization(false);
- }
- if (driver.GetInstructionSet() == kX86_64) {
- return X86CFIInitialization(true);
- }
- return nullptr;
-}
-
-CompiledMethod* OptimizingCompiler::Compile(const DexFile::CodeItem* code_item,
- uint32_t access_flags,
- InvokeType invoke_type,
- uint16_t class_def_idx,
- uint32_t method_idx,
- jobject class_loader,
- const DexFile& dex_file) const {
- CompiledMethod* method = TryCompile(code_item, access_flags, invoke_type, class_def_idx,
- method_idx, class_loader, dex_file);
- if (method != nullptr) {
- return method;
- }
-
- return QuickCompiler::Compile(code_item, access_flags, invoke_type, class_def_idx, method_idx,
- class_loader, dex_file);
-}
-
-} // namespace art
diff --git a/compiler/dex/quick/mir_to_lir.cc b/compiler/dex/quick/mir_to_lir.cc
index c945f7f..70ef991 100644
--- a/compiler/dex/quick/mir_to_lir.cc
+++ b/compiler/dex/quick/mir_to_lir.cc
@@ -201,6 +201,16 @@
RegStorage reg_arg_low = GetArgMappingToPhysicalReg(in_position);
RegStorage reg_arg_high = GetArgMappingToPhysicalReg(in_position + 1);
+ if (cu_->instruction_set == kX86) {
+ // Can't handle double split between reg & memory. Flush reg half to memory.
+ if (rl_dest.reg.IsDouble() && (reg_arg_low.Valid() != reg_arg_high.Valid())) {
+ DCHECK(reg_arg_low.Valid());
+ DCHECK(!reg_arg_high.Valid());
+ Store32Disp(TargetPtrReg(kSp), offset, reg_arg_low);
+ reg_arg_low = RegStorage::InvalidReg();
+ }
+ }
+
if (reg_arg_low.Valid() && reg_arg_high.Valid()) {
OpRegCopyWide(rl_dest.reg, RegStorage::MakeRegPair(reg_arg_low, reg_arg_high));
} else if (reg_arg_low.Valid() && !reg_arg_high.Valid()) {
diff --git a/compiler/optimizing/code_generator.cc b/compiler/optimizing/code_generator.cc
index 4d71cb7..0b59327 100644
--- a/compiler/optimizing/code_generator.cc
+++ b/compiler/optimizing/code_generator.cc
@@ -589,12 +589,14 @@
if (locations->RegisterContainsObject(i)) {
locations->SetStackBit(stack_offset / kVRegSize);
}
+ DCHECK_LT(stack_offset, GetFrameSize() - FrameEntrySpillSize());
stack_offset += SaveCoreRegister(stack_offset, i);
}
}
for (size_t i = 0, e = GetNumberOfFloatingPointRegisters(); i < e; ++i) {
if (register_set->ContainsFloatingPointRegister(i)) {
+ DCHECK_LT(stack_offset, GetFrameSize() - FrameEntrySpillSize());
stack_offset += SaveFloatingPointRegister(stack_offset, i);
}
}
@@ -605,12 +607,14 @@
size_t stack_offset = first_register_slot_in_slow_path_;
for (size_t i = 0, e = GetNumberOfCoreRegisters(); i < e; ++i) {
if (register_set->ContainsCoreRegister(i)) {
+ DCHECK_LT(stack_offset, GetFrameSize() - FrameEntrySpillSize());
stack_offset += RestoreCoreRegister(stack_offset, i);
}
}
for (size_t i = 0, e = GetNumberOfFloatingPointRegisters(); i < e; ++i) {
if (register_set->ContainsFloatingPointRegister(i)) {
+ DCHECK_LT(stack_offset, GetFrameSize() - FrameEntrySpillSize());
stack_offset += RestoreFloatingPointRegister(stack_offset, i);
}
}
diff --git a/compiler/optimizing/constant_folding.h b/compiler/optimizing/constant_folding.h
index d2acfa6..ac00824 100644
--- a/compiler/optimizing/constant_folding.h
+++ b/compiler/optimizing/constant_folding.h
@@ -32,10 +32,10 @@
*/
class HConstantFolding : public HOptimization {
public:
- HConstantFolding(HGraph* graph, const HGraphVisualizer& visualizer)
- : HOptimization(graph, true, kConstantFoldingPassName, visualizer) {}
+ explicit HConstantFolding(HGraph* graph)
+ : HOptimization(graph, true, kConstantFoldingPassName) {}
- virtual void Run() OVERRIDE;
+ void Run() OVERRIDE;
static constexpr const char* kConstantFoldingPassName = "constant_folding";
diff --git a/compiler/optimizing/constant_folding_test.cc b/compiler/optimizing/constant_folding_test.cc
index 856c516..a56b9d9 100644
--- a/compiler/optimizing/constant_folding_test.cc
+++ b/compiler/optimizing/constant_folding_test.cc
@@ -47,8 +47,7 @@
ASSERT_EQ(expected_before, actual_before);
x86::CodeGeneratorX86 codegen(graph);
- HGraphVisualizer visualizer(nullptr, graph, codegen, "");
- HConstantFolding(graph, visualizer).Run();
+ HConstantFolding(graph).Run();
SSAChecker ssa_checker(&allocator, graph);
ssa_checker.Run();
ASSERT_TRUE(ssa_checker.IsValid());
@@ -60,7 +59,7 @@
check_after_cf(graph);
- HDeadCodeElimination(graph, visualizer).Run();
+ HDeadCodeElimination(graph).Run();
ssa_checker.Run();
ASSERT_TRUE(ssa_checker.IsValid());
diff --git a/compiler/optimizing/dead_code_elimination.h b/compiler/optimizing/dead_code_elimination.h
index a4446ae..3db2c3f 100644
--- a/compiler/optimizing/dead_code_elimination.h
+++ b/compiler/optimizing/dead_code_elimination.h
@@ -28,10 +28,10 @@
*/
class HDeadCodeElimination : public HOptimization {
public:
- HDeadCodeElimination(HGraph* graph, const HGraphVisualizer& visualizer)
- : HOptimization(graph, true, kDeadCodeEliminationPassName, visualizer) {}
+ explicit HDeadCodeElimination(HGraph* graph)
+ : HOptimization(graph, true, kDeadCodeEliminationPassName) {}
- virtual void Run() OVERRIDE;
+ void Run() OVERRIDE;
static constexpr const char* kDeadCodeEliminationPassName =
"dead_code_elimination";
diff --git a/compiler/optimizing/dead_code_elimination_test.cc b/compiler/optimizing/dead_code_elimination_test.cc
index 0c68074..5d4b9cb 100644
--- a/compiler/optimizing/dead_code_elimination_test.cc
+++ b/compiler/optimizing/dead_code_elimination_test.cc
@@ -41,8 +41,7 @@
ASSERT_EQ(actual_before, expected_before);
x86::CodeGeneratorX86 codegen(graph);
- HGraphVisualizer visualizer(nullptr, graph, codegen, "");
- HDeadCodeElimination(graph, visualizer).Run();
+ HDeadCodeElimination(graph).Run();
SSAChecker ssa_checker(&allocator, graph);
ssa_checker.Run();
ASSERT_TRUE(ssa_checker.IsValid());
diff --git a/compiler/optimizing/gvn.h b/compiler/optimizing/gvn.h
index 8d2c774..a841d5f 100644
--- a/compiler/optimizing/gvn.h
+++ b/compiler/optimizing/gvn.h
@@ -18,6 +18,7 @@
#define ART_COMPILER_OPTIMIZING_GVN_H_
#include "nodes.h"
+#include "optimization.h"
namespace art {
@@ -165,11 +166,11 @@
/**
* Optimization phase that removes redundant instruction.
*/
-class GlobalValueNumberer : public ValueObject {
+class GlobalValueNumberer : public HOptimization {
public:
GlobalValueNumberer(ArenaAllocator* allocator, HGraph* graph)
- : allocator_(allocator),
- graph_(graph),
+ : HOptimization(graph, true, "GVN"),
+ allocator_(allocator),
block_effects_(allocator, graph->GetBlocks().Size()),
loop_effects_(allocator, graph->GetBlocks().Size()),
sets_(allocator, graph->GetBlocks().Size()),
@@ -186,7 +187,7 @@
}
}
- void Run();
+ void Run() OVERRIDE;
private:
// Per-block GVN. Will also update the ValueSet of the dominated and
@@ -202,7 +203,6 @@
SideEffects GetBlockEffects(HBasicBlock* block) const;
ArenaAllocator* const allocator_;
- HGraph* const graph_;
// Side effects of individual blocks, that is the union of the side effects
// of the instructions in the block.
diff --git a/compiler/optimizing/instruction_simplifier.cc b/compiler/optimizing/instruction_simplifier.cc
index 3e8361e..3d65e9a 100644
--- a/compiler/optimizing/instruction_simplifier.cc
+++ b/compiler/optimizing/instruction_simplifier.cc
@@ -18,11 +18,22 @@
namespace art {
+class InstructionSimplifierVisitor : public HGraphVisitor {
+ public:
+ explicit InstructionSimplifierVisitor(HGraph* graph) : HGraphVisitor(graph) {}
+
+ private:
+ void VisitSuspendCheck(HSuspendCheck* check) OVERRIDE;
+ void VisitEqual(HEqual* equal) OVERRIDE;
+ void VisitArraySet(HArraySet* equal) OVERRIDE;
+};
+
void InstructionSimplifier::Run() {
- VisitInsertionOrder();
+ InstructionSimplifierVisitor visitor(graph_);
+ visitor.VisitInsertionOrder();
}
-void InstructionSimplifier::VisitSuspendCheck(HSuspendCheck* check) {
+void InstructionSimplifierVisitor::VisitSuspendCheck(HSuspendCheck* check) {
HBasicBlock* block = check->GetBlock();
// Currently always keep the suspend check at entry.
if (block->IsEntryBlock()) return;
@@ -38,7 +49,7 @@
block->RemoveInstruction(check);
}
-void InstructionSimplifier::VisitEqual(HEqual* equal) {
+void InstructionSimplifierVisitor::VisitEqual(HEqual* equal) {
HInstruction* input1 = equal->InputAt(0);
HInstruction* input2 = equal->InputAt(1);
if (input1->GetType() == Primitive::kPrimBoolean && input2->IsIntConstant()) {
@@ -55,7 +66,7 @@
}
}
-void InstructionSimplifier::VisitArraySet(HArraySet* instruction) {
+void InstructionSimplifierVisitor::VisitArraySet(HArraySet* instruction) {
HInstruction* value = instruction->GetValue();
if (value->GetType() != Primitive::kPrimNot) return;
diff --git a/compiler/optimizing/instruction_simplifier.h b/compiler/optimizing/instruction_simplifier.h
index 3844d57..7068c7f 100644
--- a/compiler/optimizing/instruction_simplifier.h
+++ b/compiler/optimizing/instruction_simplifier.h
@@ -18,22 +18,19 @@
#define ART_COMPILER_OPTIMIZING_INSTRUCTION_SIMPLIFIER_H_
#include "nodes.h"
+#include "optimization.h"
namespace art {
/**
* Implements optimizations specific to each instruction.
*/
-class InstructionSimplifier : public HGraphVisitor {
+class InstructionSimplifier : public HOptimization {
public:
- explicit InstructionSimplifier(HGraph* graph) : HGraphVisitor(graph) {}
+ explicit InstructionSimplifier(HGraph* graph)
+ : HOptimization(graph, true, "instruction_simplifier") {}
- void Run();
-
- private:
- virtual void VisitSuspendCheck(HSuspendCheck* check) OVERRIDE;
- virtual void VisitEqual(HEqual* equal) OVERRIDE;
- virtual void VisitArraySet(HArraySet* equal) OVERRIDE;
+ void Run() OVERRIDE;
};
} // namespace art
diff --git a/compiler/optimizing/locations.h b/compiler/optimizing/locations.h
index d1555d4..e1c8e8e 100644
--- a/compiler/optimizing/locations.h
+++ b/compiler/optimizing/locations.h
@@ -391,6 +391,10 @@
return (register_set & (1 << reg)) != 0;
}
+ size_t GetNumberOfRegisters() const {
+ return __builtin_popcount(core_registers_) + __builtin_popcount(floating_point_registers_);
+ }
+
private:
uint32_t core_registers_;
uint32_t floating_point_registers_;
@@ -503,6 +507,10 @@
return &live_registers_;
}
+ size_t GetNumberOfLiveRegisters() const {
+ return live_registers_.GetNumberOfRegisters();
+ }
+
bool InputOverlapsWithOutputOrTemp(uint32_t input_index, bool is_environment) const {
if (is_environment) return true;
if ((input_index == 0)
diff --git a/compiler/optimizing/optimization.cc b/compiler/optimizing/optimization.cc
index ea98186..d1178d5 100644
--- a/compiler/optimizing/optimization.cc
+++ b/compiler/optimizing/optimization.cc
@@ -21,12 +21,6 @@
namespace art {
-void HOptimization::Execute() {
- Run();
- visualizer_.DumpGraph(pass_name_);
- Check();
-}
-
void HOptimization::Check() {
if (kIsDebugBuild) {
if (is_in_ssa_form_) {
diff --git a/compiler/optimizing/optimization.h b/compiler/optimizing/optimization.h
index 59683e2..d281248 100644
--- a/compiler/optimizing/optimization.h
+++ b/compiler/optimizing/optimization.h
@@ -29,25 +29,19 @@
public:
HOptimization(HGraph* graph,
bool is_in_ssa_form,
- const char* pass_name,
- const HGraphVisualizer& visualizer)
+ const char* pass_name)
: graph_(graph),
is_in_ssa_form_(is_in_ssa_form),
- pass_name_(pass_name),
- visualizer_(visualizer) {}
+ pass_name_(pass_name) {}
virtual ~HOptimization() {}
- // Execute the optimization pass.
- void Execute();
-
// Return the name of the pass.
const char* GetPassName() const { return pass_name_; }
// Peform the analysis itself.
virtual void Run() = 0;
- private:
// Verify the graph; abort if it is not valid.
void Check();
@@ -59,9 +53,6 @@
const bool is_in_ssa_form_;
// Optimization pass name.
const char* pass_name_;
- // A graph visualiser invoked after the execution of the optimization
- // pass if enabled.
- const HGraphVisualizer& visualizer_;
DISALLOW_COPY_AND_ASSIGN(HOptimization);
};
diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc
index 53273a4..42ac77d 100644
--- a/compiler/optimizing/optimizing_compiler.cc
+++ b/compiler/optimizing/optimizing_compiler.cc
@@ -190,6 +190,25 @@
return code_item.tries_size_ == 0;
}
+static void RunOptimizations(HGraph* graph, const HGraphVisualizer& visualizer) {
+ HDeadCodeElimination opt1(graph);
+ HConstantFolding opt2(graph);
+ SsaRedundantPhiElimination opt3(graph);
+ SsaDeadPhiElimination opt4(graph);
+ InstructionSimplifier opt5(graph);
+ GlobalValueNumberer opt6(graph->GetArena(), graph);
+ InstructionSimplifier opt7(graph);
+
+ HOptimization* optimizations[] = { &opt1, &opt2, &opt3, &opt4, &opt5, &opt6, &opt7 };
+
+ for (size_t i = 0; i < arraysize(optimizations); ++i) {
+ HOptimization* optimization = optimizations[i];
+ optimization->Run();
+ optimization->Check();
+ visualizer.DumpGraph(optimization->GetPassName());
+ }
+}
+
CompiledMethod* OptimizingCompiler::Compile(const DexFile::CodeItem* code_item,
uint32_t access_flags,
InvokeType invoke_type,
@@ -257,17 +276,9 @@
visualizer.DumpGraph("ssa");
graph->FindNaturalLoops();
- HDeadCodeElimination(graph, visualizer).Execute();
- HConstantFolding(graph, visualizer).Execute();
+ RunOptimizations(graph, visualizer);
- SsaRedundantPhiElimination(graph).Run();
- SsaDeadPhiElimination(graph).Run();
- InstructionSimplifier(graph).Run();
- GlobalValueNumberer(graph->GetArena(), graph).Run();
- visualizer.DumpGraph(kGVNPassName);
- InstructionSimplifier(graph).Run();
PrepareForRegisterAllocation(graph).Run();
-
SsaLivenessAnalysis liveness(*graph, codegen);
liveness.Analyze();
visualizer.DumpGraph(kLivenessPassName);
diff --git a/compiler/optimizing/register_allocator.cc b/compiler/optimizing/register_allocator.cc
index 4d6e664..2948496 100644
--- a/compiler/optimizing/register_allocator.cc
+++ b/compiler/optimizing/register_allocator.cc
@@ -215,9 +215,16 @@
// By adding the following interval in the algorithm, we can compute this
// maximum before updating locations.
LiveInterval* interval = LiveInterval::MakeSlowPathInterval(allocator_, instruction);
- interval->AddRange(position, position + 1);
- unhandled_core_intervals_.Add(interval);
- unhandled_fp_intervals_.Add(interval);
+ // The start of the interval must be after the position of the safepoint, so that
+ // we can just check the number of active registers at that position. Note that this
+ // will include the current interval in the computation of
+ // `maximum_number_of_live_registers`, so we need a better strategy if this becomes
+ // a problem.
+ // TODO: We could put the logic in AddSorted, to ensure the safepoint range is
+ // after all other intervals starting at that same position.
+ interval->AddRange(position + 1, position + 2);
+ AddSorted(&unhandled_core_intervals_, interval);
+ AddSorted(&unhandled_fp_intervals_, interval);
}
}
@@ -250,6 +257,7 @@
: unhandled_fp_intervals_;
DCHECK(unhandled.IsEmpty() || current->StartsBeforeOrAt(unhandled.Peek()));
+
// Some instructions define their output in fixed register/stack slot. We need
// to ensure we know these locations before doing register allocation. For a
// given register, we create an interval that covers these locations. The register
@@ -475,6 +483,17 @@
LiveInterval* current = unhandled_->Pop();
DCHECK(!current->IsFixed() && !current->HasSpillSlot());
DCHECK(unhandled_->IsEmpty() || unhandled_->Peek()->GetStart() >= current->GetStart());
+
+ if (current->IsSlowPathSafepoint()) {
+ // Synthesized interval to record the maximum number of live registers
+ // at safepoints. No need to allocate a register for it.
+ // We know that current actives are all live at the safepoint (modulo
+ // the one created by the safepoint).
+ maximum_number_of_live_registers_ =
+ std::max(maximum_number_of_live_registers_, active_.Size());
+ continue;
+ }
+
size_t position = current->GetStart();
// Remember the inactive_ size here since the ones moved to inactive_ from
@@ -515,14 +534,6 @@
}
}
- if (current->IsSlowPathSafepoint()) {
- // Synthesized interval to record the maximum number of live registers
- // at safepoints. No need to allocate a register for it.
- maximum_number_of_live_registers_ =
- std::max(maximum_number_of_live_registers_, active_.Size());
- continue;
- }
-
// (4) Try to find an available register.
bool success = TryAllocateFreeReg(current);
@@ -1062,6 +1073,7 @@
switch (source.GetKind()) {
case Location::kRegister: {
locations->AddLiveRegister(source);
+ DCHECK_LE(locations->GetNumberOfLiveRegisters(), maximum_number_of_live_registers_);
if (current->GetType() == Primitive::kPrimNot) {
locations->SetRegisterBit(source.reg());
}
diff --git a/compiler/optimizing/ssa_phi_elimination.h b/compiler/optimizing/ssa_phi_elimination.h
index 5274f09..b789971 100644
--- a/compiler/optimizing/ssa_phi_elimination.h
+++ b/compiler/optimizing/ssa_phi_elimination.h
@@ -18,6 +18,7 @@
#define ART_COMPILER_OPTIMIZING_SSA_PHI_ELIMINATION_H_
#include "nodes.h"
+#include "optimization.h"
namespace art {
@@ -25,15 +26,15 @@
* Optimization phase that removes dead phis from the graph. Dead phis are unused
* phis, or phis only used by other phis.
*/
-class SsaDeadPhiElimination : public ValueObject {
+class SsaDeadPhiElimination : public HOptimization {
public:
explicit SsaDeadPhiElimination(HGraph* graph)
- : graph_(graph), worklist_(graph->GetArena(), kDefaultWorklistSize) {}
+ : HOptimization(graph, true, "dead_phi_elimination"),
+ worklist_(graph->GetArena(), kDefaultWorklistSize) {}
- void Run();
+ void Run() OVERRIDE;
private:
- HGraph* const graph_;
GrowableArray<HPhi*> worklist_;
static constexpr size_t kDefaultWorklistSize = 8;
@@ -47,15 +48,15 @@
* registers might be updated with the same value, or not updated at all. We can just
* replace the phi with the value when entering the loop.
*/
-class SsaRedundantPhiElimination : public ValueObject {
+class SsaRedundantPhiElimination : public HOptimization {
public:
explicit SsaRedundantPhiElimination(HGraph* graph)
- : graph_(graph), worklist_(graph->GetArena(), kDefaultWorklistSize) {}
+ : HOptimization(graph, true, "redundant_phi_elimination"),
+ worklist_(graph->GetArena(), kDefaultWorklistSize) {}
- void Run();
+ void Run() OVERRIDE;
private:
- HGraph* const graph_;
GrowableArray<HPhi*> worklist_;
static constexpr size_t kDefaultWorklistSize = 8;
diff --git a/runtime/jni_internal_test.cc b/runtime/jni_internal_test.cc
index c24ef05..62b6b34 100644
--- a/runtime/jni_internal_test.cc
+++ b/runtime/jni_internal_test.cc
@@ -390,59 +390,72 @@
void ReleasePrimitiveArrayElementsOfWrongType(bool check_jni) {
bool old_check_jni = vm_->SetCheckJniEnabled(check_jni);
CheckJniAbortCatcher jni_abort_catcher;
+ {
+ jbooleanArray array = env_->NewBooleanArray(10);
+ ASSERT_TRUE(array != nullptr);
+ jboolean is_copy;
+ jboolean* elements = env_->GetBooleanArrayElements(array, &is_copy);
+ ASSERT_TRUE(elements != nullptr);
+ env_->ReleaseByteArrayElements(reinterpret_cast<jbyteArray>(array),
+ reinterpret_cast<jbyte*>(elements), 0);
+ jni_abort_catcher.Check(
+ check_jni ? "incompatible array type boolean[] expected byte[]"
+ : "attempt to release byte primitive array elements with an object of type boolean[]");
+ env_->ReleaseShortArrayElements(reinterpret_cast<jshortArray>(array),
+ reinterpret_cast<jshort*>(elements), 0);
+ jni_abort_catcher.Check(
+ check_jni ? "incompatible array type boolean[] expected short[]"
+ : "attempt to release short primitive array elements with an object of type boolean[]");
+ env_->ReleaseCharArrayElements(reinterpret_cast<jcharArray>(array),
+ reinterpret_cast<jchar*>(elements), 0);
+ jni_abort_catcher.Check(
+ check_jni ? "incompatible array type boolean[] expected char[]"
+ : "attempt to release char primitive array elements with an object of type boolean[]");
+ env_->ReleaseIntArrayElements(reinterpret_cast<jintArray>(array),
+ reinterpret_cast<jint*>(elements), 0);
+ jni_abort_catcher.Check(
+ check_jni ? "incompatible array type boolean[] expected int[]"
+ : "attempt to release int primitive array elements with an object of type boolean[]");
+ env_->ReleaseLongArrayElements(reinterpret_cast<jlongArray>(array),
+ reinterpret_cast<jlong*>(elements), 0);
+ jni_abort_catcher.Check(
+ check_jni ? "incompatible array type boolean[] expected long[]"
+ : "attempt to release long primitive array elements with an object of type boolean[]");
+ env_->ReleaseFloatArrayElements(reinterpret_cast<jfloatArray>(array),
+ reinterpret_cast<jfloat*>(elements), 0);
+ jni_abort_catcher.Check(
+ check_jni ? "incompatible array type boolean[] expected float[]"
+ : "attempt to release float primitive array elements with an object of type boolean[]");
+ env_->ReleaseDoubleArrayElements(reinterpret_cast<jdoubleArray>(array),
+ reinterpret_cast<jdouble*>(elements), 0);
+ jni_abort_catcher.Check(
+ check_jni ? "incompatible array type boolean[] expected double[]"
+ : "attempt to release double primitive array elements with an object of type boolean[]");
- jbooleanArray array = env_->NewBooleanArray(10);
- ASSERT_TRUE(array != nullptr);
- jboolean is_copy;
- jboolean* elements = env_->GetBooleanArrayElements(array, &is_copy);
- ASSERT_TRUE(elements != nullptr);
- env_->ReleaseByteArrayElements(reinterpret_cast<jbyteArray>(array),
- reinterpret_cast<jbyte*>(elements), 0);
- jni_abort_catcher.Check(
- check_jni ? "incompatible array type boolean[] expected byte[]"
- : "attempt to release byte primitive array elements with an object of type boolean[]");
- env_->ReleaseShortArrayElements(reinterpret_cast<jshortArray>(array),
- reinterpret_cast<jshort*>(elements), 0);
- jni_abort_catcher.Check(
- check_jni ? "incompatible array type boolean[] expected short[]"
- : "attempt to release short primitive array elements with an object of type boolean[]");
- env_->ReleaseCharArrayElements(reinterpret_cast<jcharArray>(array),
- reinterpret_cast<jchar*>(elements), 0);
- jni_abort_catcher.Check(
- check_jni ? "incompatible array type boolean[] expected char[]"
- : "attempt to release char primitive array elements with an object of type boolean[]");
- env_->ReleaseIntArrayElements(reinterpret_cast<jintArray>(array),
- reinterpret_cast<jint*>(elements), 0);
- jni_abort_catcher.Check(
- check_jni ? "incompatible array type boolean[] expected int[]"
- : "attempt to release int primitive array elements with an object of type boolean[]");
- env_->ReleaseLongArrayElements(reinterpret_cast<jlongArray>(array),
- reinterpret_cast<jlong*>(elements), 0);
- jni_abort_catcher.Check(
- check_jni ? "incompatible array type boolean[] expected long[]"
- : "attempt to release long primitive array elements with an object of type boolean[]");
- env_->ReleaseFloatArrayElements(reinterpret_cast<jfloatArray>(array),
- reinterpret_cast<jfloat*>(elements), 0);
- jni_abort_catcher.Check(
- check_jni ? "incompatible array type boolean[] expected float[]"
- : "attempt to release float primitive array elements with an object of type boolean[]");
- env_->ReleaseDoubleArrayElements(reinterpret_cast<jdoubleArray>(array),
- reinterpret_cast<jdouble*>(elements), 0);
- jni_abort_catcher.Check(
- check_jni ? "incompatible array type boolean[] expected double[]"
- : "attempt to release double primitive array elements with an object of type boolean[]");
- jbyteArray array2 = env_->NewByteArray(10);
- env_->ReleaseBooleanArrayElements(reinterpret_cast<jbooleanArray>(array2), elements, 0);
- jni_abort_catcher.Check(
- check_jni ? "incompatible array type byte[] expected boolean[]"
- : "attempt to release boolean primitive array elements with an object of type byte[]");
- jobject object = env_->NewStringUTF("Test String");
- env_->ReleaseBooleanArrayElements(reinterpret_cast<jbooleanArray>(object), elements, 0);
- jni_abort_catcher.Check(
- check_jni ? "jarray argument has non-array type: java.lang.String"
- : "attempt to release boolean primitive array elements with an object of type "
+ // Don't leak the elements array.
+ env_->ReleaseBooleanArrayElements(array, elements, 0);
+ }
+ {
+ jbyteArray array = env_->NewByteArray(10);
+ jboolean is_copy;
+ jbyte* elements = env_->GetByteArrayElements(array, &is_copy);
+
+ env_->ReleaseBooleanArrayElements(reinterpret_cast<jbooleanArray>(array),
+ reinterpret_cast<jboolean*>(elements), 0);
+ jni_abort_catcher.Check(
+ check_jni ? "incompatible array type byte[] expected boolean[]"
+ : "attempt to release boolean primitive array elements with an object of type byte[]");
+ jobject object = env_->NewStringUTF("Test String");
+ env_->ReleaseBooleanArrayElements(reinterpret_cast<jbooleanArray>(object),
+ reinterpret_cast<jboolean*>(elements), 0);
+ jni_abort_catcher.Check(
+ check_jni ? "jarray argument has non-array type: java.lang.String"
+ : "attempt to release boolean primitive array elements with an object of type "
"java.lang.String");
+ // Don't leak the elements array.
+ env_->ReleaseByteArrayElements(array, elements, 0);
+ }
EXPECT_EQ(check_jni, vm_->SetCheckJniEnabled(old_check_jni));
}
diff --git a/test/083-compiler-regressions/expected.txt b/test/083-compiler-regressions/expected.txt
index 51bf847..78c92fc 100644
--- a/test/083-compiler-regressions/expected.txt
+++ b/test/083-compiler-regressions/expected.txt
@@ -1,3 +1,4 @@
+b17325447 passes
b17630605 passes
b17411468 passes
b2296099 passes
diff --git a/test/083-compiler-regressions/src/Main.java b/test/083-compiler-regressions/src/Main.java
index 9ad8ea7..285c360 100644
--- a/test/083-compiler-regressions/src/Main.java
+++ b/test/083-compiler-regressions/src/Main.java
@@ -30,6 +30,7 @@
}
public static void main(String args[]) throws Exception {
+ b17325447();
b17630605();
b17411468();
b2296099Test();
@@ -64,6 +65,31 @@
minDoubleWith3ConstsTest();
}
+ public static double b17325447_i1(int i1, double f) {
+ return f;
+ }
+
+ public static double b17325447_i2(int i1, int i2, double f) {
+ return f;
+ }
+
+ public static double b17325447_i3(int i1, int i2, int i3, double f) {
+ return f;
+ }
+
+ public static void b17325447() {
+ // b/17325447 - x86 handling of special identity method w/ double spanning reg/mem.
+ double d = 0.0;
+ d += b17325447_i1(123, 1.0);
+ d += b17325447_i2(123, 456, 2.0);
+ d += b17325447_i3(123, 456, 789, 3.0);
+ if (d == 6.0) {
+ System.out.println("b17325447 passes");
+ } else {
+ System.out.println("b17325447 fails: " + d);
+ }
+ }
+
public static void b17630605() {
// b/17630605 - failure to properly handle min long immediates.
long a1 = 40455547223404749L;
diff --git a/test/430-live-register-slow-path/expected.txt b/test/430-live-register-slow-path/expected.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/430-live-register-slow-path/expected.txt
diff --git a/test/430-live-register-slow-path/info.txt b/test/430-live-register-slow-path/info.txt
new file mode 100644
index 0000000..6f2af28
--- /dev/null
+++ b/test/430-live-register-slow-path/info.txt
@@ -0,0 +1,2 @@
+Regression test for the linear scan register allocator. It used
+to miscompute the number of live registers at a safepoint.
diff --git a/test/430-live-register-slow-path/src/Main.java b/test/430-live-register-slow-path/src/Main.java
new file mode 100644
index 0000000..b84e647
--- /dev/null
+++ b/test/430-live-register-slow-path/src/Main.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2014 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.
+ */
+
+public class Main {
+ public static void main(String[] args) {
+ $opt$TestSlowPath();
+ }
+
+ public static void $opt$TestSlowPath() {
+ Object[] o = bar();
+ assertEquals(0, o.length);
+ // The slowpath of the instanceof requires the live register
+ // holding `o` to be saved before going into runtime. The linear
+ // scan register allocator used to miscompute the number of
+ // live registers at a safepoint, so the place at which the register
+ // was saved was wrong.
+ doCall(o instanceof Interface[], o);
+ }
+
+ public static void assertEquals(int a, int b) {}
+ public static boolean doCall(boolean val, Object o) { return val; }
+
+ static Object[] bar() { return new Object[0]; }
+
+ static interface Interface {}
+}