Merge "Added index type of dex byte instructions."
diff --git a/compiler/common_compiler_test.cc b/compiler/common_compiler_test.cc
index 0a1e2e3..4b67884 100644
--- a/compiler/common_compiler_test.cc
+++ b/compiler/common_compiler_test.cc
@@ -182,13 +182,11 @@
}
}
- // TODO: make selectable
- Compiler::Kind compiler_kind = Compiler::kQuick;
timer_.reset(new CumulativeLogger("Compilation times"));
compiler_driver_.reset(new CompilerDriver(compiler_options_.get(),
verification_results_.get(),
method_inliner_map_.get(),
- compiler_kind, instruction_set,
+ compiler_kind_, instruction_set,
instruction_set_features_.get(),
true,
GetImageClasses(),
@@ -211,6 +209,14 @@
CompilerCallbacks::CallbackMode::kCompileApp));
}
+Compiler::Kind CommonCompilerTest::GetCompilerKind() const {
+ return compiler_kind_;
+}
+
+void CommonCompilerTest::SetCompilerKind(Compiler::Kind compiler_kind) {
+ compiler_kind_ = compiler_kind;
+}
+
void CommonCompilerTest::TearDown() {
timer_.reset();
compiler_driver_.reset();
diff --git a/compiler/common_compiler_test.h b/compiler/common_compiler_test.h
index 769319b..b828fcf 100644
--- a/compiler/common_compiler_test.h
+++ b/compiler/common_compiler_test.h
@@ -22,6 +22,7 @@
#include <vector>
#include "common_runtime_test.h"
+#include "compiler.h"
#include "oat_file.h"
namespace art {
@@ -55,7 +56,10 @@
protected:
virtual void SetUp();
- virtual void SetUpRuntimeOptions(RuntimeOptions *options);
+ virtual void SetUpRuntimeOptions(RuntimeOptions* options);
+
+ Compiler::Kind GetCompilerKind() const;
+ void SetCompilerKind(Compiler::Kind compiler_kind);
// Get the set of image classes given to the compiler-driver in SetUp. Note: the compiler
// driver assumes ownership of the set, so the test should properly release the set.
@@ -88,6 +92,7 @@
void UnreserveImageSpace();
+ Compiler::Kind compiler_kind_ = kUseOptimizingCompiler ? Compiler::kOptimizing : Compiler::kQuick;
std::unique_ptr<CompilerOptions> compiler_options_;
std::unique_ptr<VerificationResults> verification_results_;
std::unique_ptr<DexFileToMethodInlinerMap> method_inliner_map_;
@@ -103,6 +108,13 @@
std::list<std::vector<uint8_t>> header_code_and_maps_chunks_;
};
+// TODO: When non-PIC works with all compilers in use, get rid of this.
+#define TEST_DISABLED_FOR_NON_PIC_COMPILING_WITH_OPTIMIZING() \
+ if (GetCompilerKind() == Compiler::kOptimizing) { \
+ printf("WARNING: TEST DISABLED FOR NON-PIC COMPILING WITH OPTIMIZING\n"); \
+ return; \
+ }
+
} // namespace art
#endif // ART_COMPILER_COMMON_COMPILER_TEST_H_
diff --git a/compiler/dex/quick/gen_loadstore.cc b/compiler/dex/quick/gen_loadstore.cc
index aa95e77..3f89001 100644
--- a/compiler/dex/quick/gen_loadstore.cc
+++ b/compiler/dex/quick/gen_loadstore.cc
@@ -107,7 +107,9 @@
}
RegLocation Mir2Lir::LoadValue(RegLocation rl_src, RegisterClass op_kind) {
- DCHECK(!rl_src.ref || op_kind == kRefReg);
+ // If op_kind isn't a reference, rl_src should not be marked as a reference either
+ // unless we've seen type conflicts (i.e. register promotion is disabled).
+ DCHECK(op_kind == kRefReg || (!rl_src.ref || (cu_->disable_opt & (1u << kPromoteRegs)) != 0u));
rl_src = UpdateLoc(rl_src);
if (rl_src.location == kLocPhysReg) {
if (!RegClassMatches(op_kind, rl_src.reg)) {
diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h
index f737007..2d7ceae 100644
--- a/compiler/driver/compiler_driver.h
+++ b/compiler/driver/compiler_driver.h
@@ -668,7 +668,7 @@
bool dedupe_enabled_;
bool dump_stats_;
const bool dump_passes_;
- const std::string& dump_cfg_file_name_;
+ const std::string dump_cfg_file_name_;
CumulativeLogger* const timings_logger_;
diff --git a/compiler/image_test.cc b/compiler/image_test.cc
index 772cc80..7e31a7a 100644
--- a/compiler/image_test.cc
+++ b/compiler/image_test.cc
@@ -45,6 +45,7 @@
};
TEST_F(ImageTest, WriteRead) {
+ TEST_DISABLED_FOR_NON_PIC_COMPILING_WITH_OPTIMIZING();
// Create a generic location tmp file, to be the base of the .art and .oat temporary files.
ScratchFile location;
ScratchFile image_location(location, ".art");
diff --git a/compiler/optimizing/builder.cc b/compiler/optimizing/builder.cc
index bde2c70..54155db 100644
--- a/compiler/optimizing/builder.cc
+++ b/compiler/optimizing/builder.cc
@@ -306,6 +306,22 @@
}
}
+void HGraphBuilder::SplitTryBoundaryEdge(HBasicBlock* predecessor,
+ HBasicBlock* successor,
+ HTryBoundary::BoundaryKind kind,
+ const DexFile::CodeItem& code_item,
+ const DexFile::TryItem& try_item) {
+ // Split the edge with a single TryBoundary instruction.
+ HTryBoundary* try_boundary = new (arena_) HTryBoundary(kind);
+ HBasicBlock* try_entry_block = graph_->SplitEdge(predecessor, successor);
+ try_entry_block->AddInstruction(try_boundary);
+
+ // Link the TryBoundary to the handlers of `try_item`.
+ for (CatchHandlerIterator it(code_item, try_item); it.HasNext(); it.Next()) {
+ try_boundary->AddExceptionHandler(FindBlockStartingAt(it.GetHandlerAddress()));
+ }
+}
+
void HGraphBuilder::InsertTryBoundaryBlocks(const DexFile::CodeItem& code_item) {
if (code_item.tries_size_ == 0) {
return;
@@ -326,47 +342,54 @@
continue;
}
- // Find predecessors which are not covered by the same TryItem range. Such
- // edges enter the try block and will have a TryBoundary inserted.
- for (size_t i = 0; i < try_block->GetPredecessors().Size(); ++i) {
- HBasicBlock* predecessor = try_block->GetPredecessors().Get(i);
- HTryBoundary* try_boundary = nullptr;
- if (predecessor->IsSingleTryBoundary()) {
- try_boundary = predecessor->GetLastInstruction()->AsTryBoundary();
- if (try_boundary->GetNormalFlowSuccessor() == try_block
- && try_block->IsFirstIndexOfPredecessor(predecessor, i)) {
+ if (try_block->IsCatchBlock()) {
+ // Catch blocks are always considered an entry point into the TryItem in
+ // order to avoid splitting exceptional edges (they might not have been
+ // created yet). We separate the move-exception (if present) from the
+ // rest of the block and insert a TryBoundary after it, creating a
+ // landing pad for the exceptional edges.
+ HInstruction* first_insn = try_block->GetFirstInstruction();
+ HInstruction* split_position = nullptr;
+ if (first_insn->IsLoadException()) {
+ // Catch block starts with a LoadException. Split the block after the
+ // StoreLocal that must come after the load.
+ DCHECK(first_insn->GetNext()->IsStoreLocal());
+ split_position = first_insn->GetNext()->GetNext();
+ } else {
+ // Catch block does not obtain the exception. Split at the beginning
+ // to create an empty catch block.
+ split_position = first_insn;
+ }
+ DCHECK(split_position != nullptr);
+ HBasicBlock* catch_block = try_block;
+ try_block = catch_block->SplitBefore(split_position);
+ SplitTryBoundaryEdge(catch_block, try_block, HTryBoundary::kEntry, code_item, *try_item);
+ } else {
+ // For non-catch blocks, find predecessors which are not covered by the
+ // same TryItem range. Such edges enter the try block and will have
+ // a TryBoundary inserted.
+ for (size_t i = 0; i < try_block->GetPredecessors().Size(); ++i) {
+ HBasicBlock* predecessor = try_block->GetPredecessors().Get(i);
+ if (predecessor->IsSingleTryBoundary()) {
// The edge was already split because of an exit from a neighbouring
- // TryItem and `predecessor` is the block with a TryBoundary created
- // between the two original blocks. We do not split the edge again.
- DCHECK(!IsBlockInPcRange(predecessor->GetSinglePredecessor(), try_start, try_end));
- DCHECK(try_boundary->IsTryExit());
- DCHECK(!try_boundary->IsTryEntry());
- try_boundary->SetIsTryEntry();
+ // TryItem. We split it again and insert an entry point.
+ if (kIsDebugBuild) {
+ HTryBoundary* last_insn = predecessor->GetLastInstruction()->AsTryBoundary();
+ DCHECK(!last_insn->IsEntry());
+ DCHECK_EQ(last_insn->GetNormalFlowSuccessor(), try_block);
+ DCHECK(try_block->IsFirstIndexOfPredecessor(predecessor, i));
+ DCHECK(!IsBlockInPcRange(predecessor->GetSinglePredecessor(), try_start, try_end));
+ }
+ } else if (!IsBlockInPcRange(predecessor, try_start, try_end)) {
+ // This is an entry point into the TryItem and the edge has not been
+ // split yet. That means that `predecessor` is not in a TryItem, or
+ // it is in a different TryItem and we happened to iterate over this
+ // block first. We split the edge and insert an entry point.
} else {
- // This is an edge between a previously created TryBoundary and its
- // handler. We skip it because it is exceptional flow.
- DCHECK(try_block->IsCatchBlock());
- DCHECK(try_boundary->HasExceptionHandler(try_block));
+ // Not an edge on the boundary of the try block.
continue;
}
- } else if (!IsBlockInPcRange(predecessor, try_start, try_end)) {
- // This is an entry point into the TryItem and the edge has not been
- // split yet. That means that either `predecessor` is not in a TryItem,
- // or it is in a different TryItem and we happened to iterate over
- // this block first. We split the edge and `predecessor` may add its
- // own exception handlers later.
- try_boundary = new (arena_) HTryBoundary(/* is_entry */ true, /* is_exit */ false);
- HBasicBlock* try_entry_block = graph_->SplitEdge(predecessor, try_block);
- try_entry_block->AddInstruction(try_boundary);
- } else {
- // Not an edge on the boundary of the try block.
- continue;
- }
- DCHECK(try_boundary != nullptr);
-
- // Link the TryBoundary block to the handlers of this TryItem.
- for (CatchHandlerIterator it(code_item, *try_item); it.HasNext(); it.Next()) {
- try_boundary->AddExceptionHandler(FindBlockStartingAt(it.GetHandlerAddress()));
+ SplitTryBoundaryEdge(predecessor, try_block, HTryBoundary::kEntry, code_item, *try_item);
}
}
@@ -374,45 +397,37 @@
// edges exit the try block and will have a TryBoundary inserted.
for (size_t i = 0; i < try_block->GetSuccessors().Size(); ++i) {
HBasicBlock* successor = try_block->GetSuccessors().Get(i);
- HTryBoundary* try_boundary = nullptr;
- if (successor->IsSingleTryBoundary()) {
+ if (successor->IsCatchBlock()) {
+ // A catch block is always considered an entry point into its TryItem.
+ // We therefore assume this is an exit point, regardless of whether
+ // the catch block is in a different TryItem or not.
+ } else if (successor->IsSingleTryBoundary()) {
// The edge was already split because of an entry into a neighbouring
- // TryItem. We do not split the edge again.
- try_boundary = successor->GetLastInstruction()->AsTryBoundary();
- DCHECK_EQ(try_block, successor->GetSinglePredecessor());
- DCHECK(try_boundary->IsTryEntry());
- DCHECK(!try_boundary->IsTryExit());
- DCHECK(!IsBlockInPcRange(try_boundary->GetNormalFlowSuccessor(), try_start, try_end));
- try_boundary->SetIsTryExit();
+ // TryItem. We split it again and insert an exit.
+ if (kIsDebugBuild) {
+ HTryBoundary* last_insn = successor->GetLastInstruction()->AsTryBoundary();
+ DCHECK_EQ(try_block, successor->GetSinglePredecessor());
+ DCHECK(last_insn->IsEntry());
+ DCHECK(!IsBlockInPcRange(last_insn->GetNormalFlowSuccessor(), try_start, try_end));
+ }
} else if (!IsBlockInPcRange(successor, try_start, try_end)) {
// This is an exit out of the TryItem and the edge has not been split
// yet. That means that either `successor` is not in a TryItem, or it
// is in a different TryItem and we happened to iterate over this
- // block first. We split the edge and `successor` may add its own
- // exception handlers later.
+ // block first. We split the edge and insert an exit.
HInstruction* last_instruction = try_block->GetLastInstruction();
if (last_instruction->IsReturn() || last_instruction->IsReturnVoid()) {
DCHECK_EQ(successor, exit_block_);
// Control flow exits the try block with a Return(Void). Because
// splitting the edge would invalidate the invariant that Return
// always jumps to Exit, we move the Return outside the try block.
- HBasicBlock* return_block = try_block->SplitBefore(last_instruction);
- graph_->AddBlock(return_block);
- successor = return_block;
+ successor = try_block->SplitBefore(last_instruction);
}
- try_boundary = new (arena_) HTryBoundary(/* is_entry */ false, /* is_exit */ true);
- HBasicBlock* try_exit_block = graph_->SplitEdge(try_block, successor);
- try_exit_block->AddInstruction(try_boundary);
} else {
// Not an edge on the boundary of the try block.
continue;
}
- DCHECK(try_boundary != nullptr);
-
- // Link the TryBoundary block to the handlers of this TryItem.
- for (CatchHandlerIterator it(code_item, *try_item); it.HasNext(); it.Next()) {
- try_boundary->AddExceptionHandler(FindBlockStartingAt(it.GetHandlerAddress()));
- }
+ SplitTryBoundaryEdge(try_block, successor, HTryBoundary::kExit, code_item, *try_item);
}
}
}
diff --git a/compiler/optimizing/builder.h b/compiler/optimizing/builder.h
index 58d85e9..cae762b 100644
--- a/compiler/optimizing/builder.h
+++ b/compiler/optimizing/builder.h
@@ -97,10 +97,26 @@
void MaybeUpdateCurrentBlock(size_t dex_pc);
HBasicBlock* FindBlockStartingAt(int32_t dex_pc) const;
HBasicBlock* FindOrCreateBlockStartingAt(int32_t dex_pc);
+
+ // Returns whether the dex_pc of `block` lies within the given range.
bool IsBlockInPcRange(HBasicBlock* block, uint32_t dex_pc_start, uint32_t dex_pc_end);
+
+ // Adds new blocks to `branch_targets_` starting at the limits of TryItems and
+ // their exception handlers.
void CreateBlocksForTryCatch(const DexFile::CodeItem& code_item);
+
+ // Splits edges which cross the boundaries of TryItems, inserts TryBoundary
+ // instructions and links them to the corresponding catch blocks.
void InsertTryBoundaryBlocks(const DexFile::CodeItem& code_item);
+ // Splits a single edge, inserting a TryBoundary of given `kind` and linking
+ // it to exception handlers of `try_item`.
+ void SplitTryBoundaryEdge(HBasicBlock* predecessor,
+ HBasicBlock* successor,
+ HTryBoundary::BoundaryKind kind,
+ const DexFile::CodeItem& code_item,
+ const DexFile::TryItem& try_item);
+
void InitializeLocals(uint16_t count);
HLocal* GetLocalAt(int register_index) const;
void UpdateLocal(int register_index, HInstruction* instruction) const;
diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc
index ff9373a..39c316f 100644
--- a/compiler/optimizing/code_generator_arm.cc
+++ b/compiler/optimizing/code_generator_arm.cc
@@ -1030,9 +1030,8 @@
if (!cond->IsCondition() || cond->AsCondition()->NeedsMaterialization()) {
// Condition has been materialized, compare the output to 0
DCHECK(instruction->GetLocations()->InAt(0).IsRegister());
- __ cmp(instruction->GetLocations()->InAt(0).AsRegister<Register>(),
- ShifterOperand(0));
- __ b(true_target, NE);
+ __ CompareAndBranchIfNonZero(instruction->GetLocations()->InAt(0).AsRegister<Register>(),
+ true_target);
} else {
// Condition has not been materialized, use its inputs as the
// comparison and its condition as the branch condition.
@@ -2591,8 +2590,7 @@
switch (instruction->GetType()) {
case Primitive::kPrimInt: {
if (value.IsRegister()) {
- __ cmp(value.AsRegister<Register>(), ShifterOperand(0));
- __ b(slow_path->GetEntryLabel(), EQ);
+ __ CompareAndBranchIfZero(value.AsRegister<Register>(), slow_path->GetEntryLabel());
} else {
DCHECK(value.IsConstant()) << value;
if (value.GetConstant()->AsIntConstant()->GetValue() == 0) {
@@ -3011,8 +3009,7 @@
__ ldrexd(temp1, temp2, addr);
codegen_->MaybeRecordImplicitNullCheck(instruction);
__ strexd(temp1, value_lo, value_hi, addr);
- __ cmp(temp1, ShifterOperand(0));
- __ b(&fail, NE);
+ __ CompareAndBranchIfNonZero(temp1, &fail);
}
void LocationsBuilderARM::HandleFieldSet(HInstruction* instruction, const FieldInfo& field_info) {
@@ -3328,8 +3325,7 @@
LocationSummary* locations = instruction->GetLocations();
Location obj = locations->InAt(0);
- __ cmp(obj.AsRegister<Register>(), ShifterOperand(0));
- __ b(slow_path->GetEntryLabel(), EQ);
+ __ CompareAndBranchIfZero(obj.AsRegister<Register>(), slow_path->GetEntryLabel());
}
void InstructionCodeGeneratorARM::VisitNullCheck(HNullCheck* instruction) {
@@ -3746,13 +3742,11 @@
__ LoadFromOffset(
kLoadUnsignedHalfword, IP, TR, Thread::ThreadFlagsOffset<kArmWordSize>().Int32Value());
- __ cmp(IP, ShifterOperand(0));
- // TODO: Figure out the branch offsets and use cbz/cbnz.
if (successor == nullptr) {
- __ b(slow_path->GetEntryLabel(), NE);
+ __ CompareAndBranchIfNonZero(IP, slow_path->GetEntryLabel());
__ Bind(slow_path->GetReturnLabel());
} else {
- __ b(codegen_->GetLabelOf(successor), EQ);
+ __ CompareAndBranchIfZero(IP, codegen_->GetLabelOf(successor));
__ b(slow_path->GetEntryLabel());
}
}
@@ -4004,8 +3998,7 @@
SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathARM(
cls, cls, cls->GetDexPc(), cls->MustGenerateClinitCheck());
codegen_->AddSlowPath(slow_path);
- __ cmp(out, ShifterOperand(0));
- __ b(slow_path->GetEntryLabel(), EQ);
+ __ CompareAndBranchIfZero(out, slow_path->GetEntryLabel());
if (cls->MustGenerateClinitCheck()) {
GenerateClassInitializationCheck(slow_path, out);
} else {
@@ -4061,8 +4054,7 @@
kLoadWord, out, current_method, ArtMethod::DeclaringClassOffset().Int32Value());
__ LoadFromOffset(kLoadWord, out, out, mirror::Class::DexCacheStringsOffset().Int32Value());
__ LoadFromOffset(kLoadWord, out, out, CodeGenerator::GetCacheOffset(load->GetStringIndex()));
- __ cmp(out, ShifterOperand(0));
- __ b(slow_path->GetEntryLabel(), EQ);
+ __ CompareAndBranchIfZero(out, slow_path->GetEntryLabel());
__ Bind(slow_path->GetExitLabel());
}
diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc
index 6c82fe9..931d751 100644
--- a/compiler/optimizing/code_generator_x86.cc
+++ b/compiler/optimizing/code_generator_x86.cc
@@ -3856,7 +3856,7 @@
} else {
DCHECK(value.IsConstant()) << value;
__ movl(Address(obj, offset),
- Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
+ Immediate(CodeGenerator::GetInt32ValueOf(value.GetConstant())));
}
} else {
DCHECK(index.IsRegister()) << index;
@@ -3866,7 +3866,7 @@
} else {
DCHECK(value.IsConstant()) << value;
__ movl(Address(obj, index.AsRegister<Register>(), TIMES_4, data_offset),
- Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
+ Immediate(CodeGenerator::GetInt32ValueOf(value.GetConstant())));
}
}
codegen_->MaybeRecordImplicitNullCheck(instruction);
diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc
index 22f5d96..afffbe2 100644
--- a/compiler/optimizing/code_generator_x86_64.cc
+++ b/compiler/optimizing/code_generator_x86_64.cc
@@ -3337,7 +3337,7 @@
case Primitive::kPrimNot: {
if (value.IsConstant()) {
int32_t v = CodeGenerator::GetInt32ValueOf(value.GetConstant());
- __ movw(Address(base, offset), Immediate(v));
+ __ movl(Address(base, offset), Immediate(v));
} else {
__ movl(Address(base, offset), value.AsRegister<CpuRegister>());
}
diff --git a/compiler/optimizing/graph_visualizer.cc b/compiler/optimizing/graph_visualizer.cc
index c41574c..504c141 100644
--- a/compiler/optimizing/graph_visualizer.cc
+++ b/compiler/optimizing/graph_visualizer.cc
@@ -152,7 +152,7 @@
/**
* HGraph visitor to generate a file suitable for the c1visualizer tool and IRHydra.
*/
-class HGraphVisualizerPrinter : public HGraphVisitor {
+class HGraphVisualizerPrinter : public HGraphDelegateVisitor {
public:
HGraphVisualizerPrinter(HGraph* graph,
std::ostream& output,
@@ -160,7 +160,7 @@
bool is_after_pass,
const CodeGenerator& codegen,
const DisassemblyInformation* disasm_info = nullptr)
- : HGraphVisitor(graph),
+ : HGraphDelegateVisitor(graph),
output_(output),
pass_name_(pass_name),
is_after_pass_(is_after_pass),
@@ -372,20 +372,21 @@
<< instance_of->MustDoNullCheck() << std::noboolalpha;
}
- void VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) OVERRIDE {
+ void VisitInvoke(HInvoke* invoke) OVERRIDE {
StartAttributeStream("dex_file_index") << invoke->GetDexMethodIndex();
+ StartAttributeStream("method_name") << PrettyMethod(
+ invoke->GetDexMethodIndex(), GetGraph()->GetDexFile(), /* with_signature */ false);
+ }
+
+ void VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) OVERRIDE {
+ VisitInvoke(invoke);
StartAttributeStream("recursive") << std::boolalpha
<< invoke->IsRecursive()
<< std::noboolalpha;
}
void VisitTryBoundary(HTryBoundary* try_boundary) OVERRIDE {
- StartAttributeStream("is_entry") << std::boolalpha
- << try_boundary->IsTryEntry()
- << std::noboolalpha;
- StartAttributeStream("is_exit") << std::boolalpha
- << try_boundary->IsTryExit()
- << std::noboolalpha;
+ StartAttributeStream("kind") << (try_boundary->IsEntry() ? "entry" : "exit");
}
bool IsPass(const char* name) {
diff --git a/compiler/optimizing/instruction_simplifier.cc b/compiler/optimizing/instruction_simplifier.cc
index e375f7b..62f90c2 100644
--- a/compiler/optimizing/instruction_simplifier.cc
+++ b/compiler/optimizing/instruction_simplifier.cc
@@ -398,6 +398,10 @@
}
}
+ if (value->IsNullConstant()) {
+ instruction->ClearNeedsTypeCheck();
+ }
+
if (!value->CanBeNull()) {
instruction->ClearValueCanBeNull();
}
diff --git a/compiler/optimizing/locations.cc b/compiler/optimizing/locations.cc
index 42aba04..d14dfc1 100644
--- a/compiler/optimizing/locations.cc
+++ b/compiler/optimizing/locations.cc
@@ -51,16 +51,17 @@
}
Location Location::RegisterOrInt32LongConstant(HInstruction* instruction) {
- if (!instruction->IsConstant() || !instruction->AsConstant()->IsLongConstant()) {
+ if (instruction->IsIntConstant() || instruction->IsNullConstant()) {
+ return Location::ConstantLocation(instruction->AsConstant());
+ } else if (instruction->IsLongConstant()) {
+ // Does the long constant fit in a 32 bit int?
+ int64_t value = instruction->AsLongConstant()->GetValue();
+ return IsInt<32>(value)
+ ? Location::ConstantLocation(instruction->AsConstant())
+ : Location::RequiresRegister();
+ } else {
return Location::RequiresRegister();
}
-
- // Does the long constant fit in a 32 bit int?
- int64_t value = instruction->AsConstant()->AsLongConstant()->GetValue();
-
- return IsInt<32>(value)
- ? Location::ConstantLocation(instruction->AsConstant())
- : Location::RequiresRegister();
}
Location Location::ByteRegisterOrConstant(int reg, HInstruction* instruction) {
diff --git a/compiler/optimizing/nodes.cc b/compiler/optimizing/nodes.cc
index 881f9ec..b82e37c 100644
--- a/compiler/optimizing/nodes.cc
+++ b/compiler/optimizing/nodes.cc
@@ -1050,6 +1050,7 @@
successors_.Reset();
AddSuccessor(new_block);
+ GetGraph()->AddBlock(new_block);
return new_block;
}
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index 95ea966..04c3963 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -729,9 +729,10 @@
bool IsExceptionalSuccessor(size_t idx) const;
// Split the block into two blocks just before `cursor`. Returns the newly
- // created, latter block. Note that this method will create a Goto at the end
- // of the former block and will create an edge between them. It will not,
- // however, update the graph, reverse post order or loop information.
+ // created, latter block. Note that this method will add the block to the
+ // graph, create a Goto at the end of the former block and will create an edge
+ // between the blocks. It will not, however, update the reverse post order or
+ // loop information.
HBasicBlock* SplitBefore(HInstruction* cursor);
// Split the block into two blocks just after `cursor`. Returns the newly
@@ -1946,8 +1947,13 @@
// higher indices in no particular order.
class HTryBoundary : public HTemplateInstruction<0> {
public:
- HTryBoundary(bool is_entry, bool is_exit)
- : HTemplateInstruction(SideEffects::None()), is_entry_(is_entry), is_exit_(is_exit) {}
+ enum BoundaryKind {
+ kEntry,
+ kExit,
+ };
+
+ explicit HTryBoundary(BoundaryKind kind)
+ : HTemplateInstruction(SideEffects::None()), kind_(kind) {}
bool IsControlFlow() const OVERRIDE { return true; }
@@ -1977,21 +1983,12 @@
}
}
- bool IsTryEntry() const { return is_entry_; }
- bool IsTryExit() const { return is_exit_; }
+ bool IsEntry() const { return kind_ == BoundaryKind::kEntry; }
DECLARE_INSTRUCTION(TryBoundary);
private:
- // Only for debugging purposes.
- bool is_entry_;
- bool is_exit_;
-
- // Only set by HGraphBuilder.
- void SetIsTryEntry() { is_entry_ = true; }
- void SetIsTryExit() { is_exit_ = true; }
-
- friend HGraphBuilder;
+ const BoundaryKind kind_;
DISALLOW_COPY_AND_ASSIGN(HTryBoundary);
};
diff --git a/compiler/utils/arm/assembler_thumb2.cc b/compiler/utils/arm/assembler_thumb2.cc
index f9e1ac6..2dde014 100644
--- a/compiler/utils/arm/assembler_thumb2.cc
+++ b/compiler/utils/arm/assembler_thumb2.cc
@@ -3341,7 +3341,7 @@
void Thumb2Assembler::CompareAndBranchIfZero(Register r, Label* label) {
- if (CanRelocateBranches() && IsLowRegister(r)) {
+ if (CanRelocateBranches() && IsLowRegister(r) && !label->IsBound()) {
cbz(r, label);
} else {
cmp(r, ShifterOperand(0));
@@ -3351,7 +3351,7 @@
void Thumb2Assembler::CompareAndBranchIfNonZero(Register r, Label* label) {
- if (CanRelocateBranches() && IsLowRegister(r)) {
+ if (CanRelocateBranches() && IsLowRegister(r) && !label->IsBound()) {
cbnz(r, label);
} else {
cmp(r, ShifterOperand(0));
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index 7a23746..74d5c0c 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -1038,6 +1038,10 @@
bool OpenFile() {
bool create_file = !oat_unstripped_.empty(); // as opposed to using open file descriptor
if (create_file) {
+ // We're supposed to create this file. If the file already exists, it may be in use currently.
+ // We must not change the content of that file, then. So unlink it first.
+ unlink(oat_unstripped_.c_str());
+
oat_file_.reset(OS::CreateEmptyFile(oat_unstripped_.c_str()));
if (oat_location_.empty()) {
oat_location_ = oat_filename_;
diff --git a/runtime/Android.mk b/runtime/Android.mk
index 5ed6955..19079cb 100644
--- a/runtime/Android.mk
+++ b/runtime/Android.mk
@@ -478,7 +478,7 @@
# For liblog, atrace, properties, ashmem, set_sched_policy and socket_peer_is_trusted.
LOCAL_SHARED_LIBRARIES += libcutils
else # host
- LOCAL_SHARED_LIBRARIES += libziparchive-host
+ LOCAL_SHARED_LIBRARIES += libziparchive-host libz-host
# For ashmem_create_region.
LOCAL_SHARED_LIBRARIES += libcutils
endif
diff --git a/runtime/arch/arm64/quick_entrypoints_arm64.S b/runtime/arch/arm64/quick_entrypoints_arm64.S
index f3c111f..614936b 100644
--- a/runtime/arch/arm64/quick_entrypoints_arm64.S
+++ b/runtime/arch/arm64/quick_entrypoints_arm64.S
@@ -1206,6 +1206,7 @@
lsr x0, x0, #7
strb w3, [x3, x0]
ret
+ .cfi_adjust_cfa_offset 32 // 4 restores after cbz for unwinding.
.Lthrow_array_store_exception:
ldp x2, x30, [sp, #16]
.cfi_restore x2
diff --git a/runtime/arch/x86/quick_entrypoints_x86.S b/runtime/arch/x86/quick_entrypoints_x86.S
index 98d0812..c9bc977 100644
--- a/runtime/arch/x86/quick_entrypoints_x86.S
+++ b/runtime/arch/x86/quick_entrypoints_x86.S
@@ -1185,9 +1185,9 @@
pushl MIRROR_OBJECT_CLASS_OFFSET(%edx) // pass arg2 - type of the value to be stored
#endif
CFI_ADJUST_CFA_OFFSET(4)
- PUSH ebx // pass arg1 - component type of the array
+ PUSH ebx // pass arg1 - component type of the array
call SYMBOL(artIsAssignableFromCode) // (Class* a, Class* b)
- addl LITERAL(16), %esp // pop arguments
+ addl LITERAL(16), %esp // pop arguments
CFI_ADJUST_CFA_OFFSET(-16)
testl %eax, %eax
jz .Lthrow_array_store_exception
@@ -1200,6 +1200,7 @@
shrl LITERAL(7), %eax
movb %dl, (%edx, %eax)
ret
+ CFI_ADJUST_CFA_OFFSET(12) // 3 POP after the jz for unwinding.
.Lthrow_array_store_exception:
POP edx
POP ecx
diff --git a/runtime/arch/x86_64/quick_entrypoints_x86_64.S b/runtime/arch/x86_64/quick_entrypoints_x86_64.S
index 259cf97..7d86c3a 100644
--- a/runtime/arch/x86_64/quick_entrypoints_x86_64.S
+++ b/runtime/arch/x86_64/quick_entrypoints_x86_64.S
@@ -1256,6 +1256,7 @@
movb %dl, (%rdx, %rdi) // Note: this assumes that top 32b of %rdi are zero
// movb %dl, (%rdx, %rdi)
ret
+ CFI_ADJUST_CFA_OFFSET(32 + 4 * 8) // Reset unwind info so following code unwinds.
.Lthrow_array_store_exception:
RESTORE_FP_CALLEE_SAVE_FRAME
// Restore arguments.
diff --git a/runtime/java_vm_ext.cc b/runtime/java_vm_ext.cc
index eb9c32d..f1deacf 100644
--- a/runtime/java_vm_ext.cc
+++ b/runtime/java_vm_ext.cc
@@ -132,6 +132,8 @@
}
void* FindSymbol(const std::string& symbol_name) {
+ CHECK(!NeedsNativeBridge());
+
return dlsym(handle_, symbol_name.c_str());
}
@@ -234,9 +236,6 @@
fn = library->FindSymbol(jni_long_name);
}
}
- if (fn == nullptr) {
- fn = library->FindSymbol(jni_long_name);
- }
if (fn != nullptr) {
VLOG(jni) << "[Found native code for " << PrettyMethod(m)
<< " in \"" << library->GetPath() << "\"]";
diff --git a/runtime/zip_archive.cc b/runtime/zip_archive.cc
index 88c1f69..9daaf8e 100644
--- a/runtime/zip_archive.cc
+++ b/runtime/zip_archive.cc
@@ -124,7 +124,7 @@
// Resist the urge to delete the space. <: is a bigraph sequence.
std::unique_ptr< ::ZipEntry> zip_entry(new ::ZipEntry);
- const int32_t error = FindEntry(handle_, ZipEntryName(name), zip_entry.get());
+ const int32_t error = FindEntry(handle_, ZipString(name), zip_entry.get());
if (error) {
*error_msg = std::string(ErrorCodeString(error));
return nullptr;
diff --git a/test/036-finalizer/src/Main.java b/test/036-finalizer/src/Main.java
index e3cf4ee..8c7c27d 100644
--- a/test/036-finalizer/src/Main.java
+++ b/test/036-finalizer/src/Main.java
@@ -34,31 +34,10 @@
}
public static WeakReference<FinalizerTest> makeRef() {
- /*
- * Make ft in another thread, so there is no danger of
- * a conservative reference leaking onto the main thread's
- * stack.
- */
-
- final List<WeakReference<FinalizerTest>> wimp =
- new ArrayList<WeakReference<FinalizerTest>>();
- Thread t = new Thread() {
- public void run() {
- FinalizerTest ft = new FinalizerTest("wahoo");
- wimp.add(new WeakReference<FinalizerTest>(ft));
- ft = null;
- }
- };
-
- t.start();
-
- try {
- t.join();
- } catch (InterruptedException ie) {
- throw new RuntimeException(ie);
- }
-
- return wimp.get(0);
+ FinalizerTest ft = new FinalizerTest("wahoo");
+ WeakReference<FinalizerTest> ref = new WeakReference<FinalizerTest>(ft);
+ ft = null;
+ return ref;
}
public static String wimpString(final WeakReference<FinalizerTest> wimp) {
@@ -91,10 +70,12 @@
public static void main(String[] args) {
WeakReference<FinalizerTest> wimp = makeRef();
+ FinalizerTest keepLive = wimp.get();
System.out.println("wimp: " + wimpString(wimp));
/* this will try to collect and finalize ft */
+ keepLive = null;
System.out.println("gc");
Runtime.getRuntime().gc();
diff --git a/test/099-vmdebug/src/Main.java b/test/099-vmdebug/src/Main.java
index a8db069..add2ff6 100644
--- a/test/099-vmdebug/src/Main.java
+++ b/test/099-vmdebug/src/Main.java
@@ -20,6 +20,9 @@
import java.util.Map;
public class Main {
+ private static final String TEMP_FILE_NAME_PREFIX = "test";
+ private static final String TEMP_FILE_NAME_SUFFIX = ".trace";
+
public static void main(String[] args) throws Exception {
String name = System.getProperty("java.vm.name");
if (!"Dalvik".equals(name)) {
@@ -32,21 +35,31 @@
private static File createTempFile() throws Exception {
try {
- return File.createTempFile("test", ".trace");
+ return File.createTempFile(TEMP_FILE_NAME_PREFIX, TEMP_FILE_NAME_SUFFIX);
} catch (IOException e) {
System.setProperty("java.io.tmpdir", "/data/local/tmp");
try {
- return File.createTempFile("test", ".trace");
+ return File.createTempFile(TEMP_FILE_NAME_PREFIX, TEMP_FILE_NAME_SUFFIX);
} catch (IOException e2) {
System.setProperty("java.io.tmpdir", "/sdcard");
- return File.createTempFile("test", ".trace");
+ return File.createTempFile(TEMP_FILE_NAME_PREFIX, TEMP_FILE_NAME_SUFFIX);
}
}
}
private static void testMethodTracing() throws Exception {
- File tempFile = createTempFile();
- tempFile.deleteOnExit();
+ File tempFile = null;
+ try {
+ tempFile = createTempFile();
+ testMethodTracingToFile(tempFile);
+ } finally {
+ if (tempFile != null) {
+ tempFile.delete();
+ }
+ }
+ }
+
+ private static void testMethodTracingToFile(File tempFile) throws Exception {
String tempFileName = tempFile.getPath();
if (VMDebug.getMethodTracingMode() != 0) {
diff --git a/test/510-checker-try-catch/smali/Builder.smali b/test/510-checker-try-catch/smali/Builder.smali
index f300b21..95708a2 100644
--- a/test/510-checker-try-catch/smali/Builder.smali
+++ b/test/510-checker-try-catch/smali/Builder.smali
@@ -68,25 +68,25 @@
## CHECK: predecessors "B0"
## CHECK: successors "<<BTry1>>"
## CHECK: xhandlers "<<BCatch1>>" "<<BCatch3>>"
-## CHECK: TryBoundary is_entry:true is_exit:false
+## CHECK: TryBoundary kind:entry
## CHECK: name "<<BExitTry1>>"
## CHECK: predecessors "<<BTry1>>"
## CHECK: successors "<<BAdd>>"
## CHECK: xhandlers "<<BCatch1>>" "<<BCatch3>>"
-## CHECK: TryBoundary is_entry:false is_exit:true
+## CHECK: TryBoundary kind:exit
## CHECK: name "<<BEnterTry2>>"
## CHECK: predecessors "<<BAdd>>"
## CHECK: successors "<<BTry2>>"
## CHECK: xhandlers "<<BCatch2>>" "<<BCatch3>>"
-## CHECK: TryBoundary is_entry:true is_exit:false
+## CHECK: TryBoundary kind:entry
## CHECK: name "<<BExitTry2>>"
## CHECK: predecessors "<<BTry2>>"
## CHECK: successors "<<BReturn>>"
## CHECK: xhandlers "<<BCatch2>>" "<<BCatch3>>"
-## CHECK: TryBoundary is_entry:false is_exit:true
+## CHECK: TryBoundary kind:exit
.method public static testMultipleTryCatch(III)I
.registers 3
@@ -164,19 +164,19 @@
## CHECK: predecessors "<<BThen>>"
## CHECK: successors "<<BTry1>>"
## CHECK: xhandlers "<<BCatch>>"
-## CHECK: TryBoundary is_entry:true is_exit:false
+## CHECK: TryBoundary kind:entry
## CHECK: name "<<BEnterTry2>>"
## CHECK: predecessors "<<BIf>>"
## CHECK: successors "<<BTry2>>"
## CHECK: xhandlers "<<BCatch>>"
-## CHECK: TryBoundary is_entry:true is_exit:false
+## CHECK: TryBoundary kind:entry
## CHECK: name "<<BExitTry>>"
## CHECK: predecessors "<<BTry2>>"
## CHECK: successors "<<BReturn>>"
## CHECK: xhandlers "<<BCatch>>"
-## CHECK: TryBoundary is_entry:false is_exit:true
+## CHECK: TryBoundary kind:exit
.method public static testMultipleEntries(IIII)I
.registers 4
@@ -237,19 +237,19 @@
## CHECK: predecessors "B0"
## CHECK: successors "<<BTry>>"
## CHECK: xhandlers "<<BCatch>>"
-## CHECK: TryBoundary is_entry:true is_exit:false
+## CHECK: TryBoundary kind:entry
## CHECK: name "<<BExitTry1>>"
## CHECK: predecessors "<<BTry>>"
## CHECK: successors "<<BThen>>"
## CHECK: xhandlers "<<BCatch>>"
-## CHECK: TryBoundary is_entry:false is_exit:true
+## CHECK: TryBoundary kind:exit
## CHECK: name "<<BExitTry2>>"
## CHECK: predecessors "<<BTry>>"
## CHECK: successors "<<BReturn>>"
## CHECK: xhandlers "<<BCatch>>"
-## CHECK: TryBoundary is_entry:false is_exit:true
+## CHECK: TryBoundary kind:exit
.method public static testMultipleExits(II)I
.registers 2
@@ -284,11 +284,11 @@
## CHECK: name "<<BTry1:B\d+>>"
## CHECK: predecessors "<<BEnter1>>"
-## CHECK: successors "<<BExit1Enter2:B\d+>>"
+## CHECK: successors "<<BExit1:B\d+>>"
## CHECK: Div
## CHECK: name "<<BTry2:B\d+>>"
-## CHECK: predecessors "<<BExit1Enter2>>"
+## CHECK: predecessors "<<BEnter2:B\d+>>"
## CHECK: successors "<<BExit2:B\d+>>"
## CHECK: Div
@@ -297,13 +297,13 @@
## CHECK: Return
## CHECK: name "<<BCatch1>>"
-## CHECK: predecessors "<<BEnter1>>" "<<BExit1Enter2>>"
+## CHECK: predecessors "<<BEnter1>>" "<<BExit1>>"
## CHECK: successors "<<BReturn>>"
## CHECK: flags "catch_block"
## CHECK: StoreLocal [v0,<<Minus1>>]
## CHECK: name "<<BCatch2>>"
-## CHECK: predecessors "<<BExit1Enter2>>" "<<BExit2>>"
+## CHECK: predecessors "<<BEnter2>>" "<<BExit2>>"
## CHECK: successors "<<BReturn>>"
## CHECK: flags "catch_block"
## CHECK: StoreLocal [v0,<<Minus2>>]
@@ -312,19 +312,25 @@
## CHECK: predecessors "B0"
## CHECK: successors "<<BTry1>>"
## CHECK: xhandlers "<<BCatch1>>"
-## CHECK: TryBoundary is_entry:true is_exit:false
+## CHECK: TryBoundary kind:entry
-## CHECK: name "<<BExit1Enter2>>"
+## CHECK: name "<<BExit1>>"
## CHECK: predecessors "<<BTry1>>"
+## CHECK: successors "<<BEnter2>>"
+## CHECK: xhandlers "<<BCatch1>>"
+## CHECK: TryBoundary kind:exit
+
+## CHECK: name "<<BEnter2>>"
+## CHECK: predecessors "<<BExit1>>"
## CHECK: successors "<<BTry2>>"
-## CHECK: xhandlers "<<BCatch1>>" "<<BCatch2>>"
-## CHECK: TryBoundary is_entry:true is_exit:true
+## CHECK: xhandlers "<<BCatch2>>"
+## CHECK: TryBoundary kind:entry
## CHECK: name "<<BExit2>>"
## CHECK: predecessors "<<BTry2>>"
## CHECK: successors "<<BReturn>>"
## CHECK: xhandlers "<<BCatch2>>"
-## CHECK: TryBoundary is_entry:false is_exit:true
+## CHECK: TryBoundary kind:exit
.method public static testSharedBoundary(III)I
.registers 3
@@ -365,13 +371,13 @@
## CHECK: Goto
## CHECK: name "<<BTry1:B\d+>>"
-## CHECK: predecessors "<<BExit2Enter1:B\d+>>"
+## CHECK: predecessors "<<BEnter1:B\d+>>"
## CHECK: successors "<<BExit1:B\d+>>"
## CHECK: Div
## CHECK: name "<<BTry2:B\d+>>"
## CHECK: predecessors "<<BEnter2>>"
-## CHECK: successors "<<BExit2Enter1>>"
+## CHECK: successors "<<BExit2:B\d+>>"
## CHECK: Div
## CHECK: name "<<BReturn:B\d+>>"
@@ -379,34 +385,40 @@
## CHECK: Return
## CHECK: name "<<BCatch1>>"
-## CHECK: predecessors "<<BExit2Enter1>>" "<<BExit1>>"
+## CHECK: predecessors "<<BEnter1>>" "<<BExit1>>"
## CHECK: successors "<<BReturn>>"
## CHECK: flags "catch_block"
## CHECK: StoreLocal [v0,<<Minus1>>]
## CHECK: name "<<BCatch2>>"
-## CHECK: predecessors "<<BEnter2>>" "<<BExit2Enter1>>"
+## CHECK: predecessors "<<BEnter2>>" "<<BExit2>>"
## CHECK: successors "<<BReturn>>"
## CHECK: flags "catch_block"
## CHECK: StoreLocal [v0,<<Minus2>>]
-## CHECK: name "<<BExit2Enter1>>"
-## CHECK: predecessors "<<BTry2>>"
+## CHECK: name "<<BEnter1>>"
+## CHECK: predecessors "<<BExit2>>"
## CHECK: successors "<<BTry1>>"
-## CHECK: xhandlers "<<BCatch1>>" "<<BCatch2>>"
-## CHECK: TryBoundary is_entry:true is_exit:true
+## CHECK: xhandlers "<<BCatch1>>"
+## CHECK: TryBoundary kind:entry
## CHECK: name "<<BExit1>>"
## CHECK: predecessors "<<BTry1>>"
## CHECK: successors "<<BReturn>>"
## CHECK: xhandlers "<<BCatch1>>"
-## CHECK: TryBoundary is_entry:false is_exit:true
+## CHECK: TryBoundary kind:exit
## CHECK: name "<<BEnter2>>"
## CHECK: predecessors "<<BGoto>>"
## CHECK: successors "<<BTry2>>"
## CHECK: xhandlers "<<BCatch2>>"
-## CHECK: TryBoundary is_entry:true is_exit:false
+## CHECK: TryBoundary kind:entry
+
+## CHECK: name "<<BExit2>>"
+## CHECK: predecessors "<<BTry2>>"
+## CHECK: successors "<<BEnter1>>"
+## CHECK: xhandlers "<<BCatch2>>"
+## CHECK: TryBoundary kind:exit
.method public static testSharedBoundary_Reverse(III)I
.registers 3
@@ -448,16 +460,16 @@
## CHECK: name "<<BTry1:B\d+>>"
## CHECK: predecessors "<<BEnter1:B\d+>>"
-## CHECK: successors "<<BExit1Enter2:B\d+>>"
+## CHECK: successors "<<BExit1:B\d+>>"
## CHECK: Div
## CHECK: name "<<BTry2:B\d+>>"
-## CHECK: predecessors "<<BExit1Enter2>>"
-## CHECK: successors "<<BExit2Enter3:B\d+>>"
+## CHECK: predecessors "<<BEnter2:B\d+>>"
+## CHECK: successors "<<BExit2:B\d+>>"
## CHECK: Div
## CHECK: name "<<BTry3:B\d+>>"
-## CHECK: predecessors "<<BExit2Enter3>>"
+## CHECK: predecessors "<<BEnter3:B\d+>>"
## CHECK: successors "<<BExit3:B\d+>>"
## CHECK: Div
@@ -465,13 +477,13 @@
## CHECK: predecessors "<<BExit3>>" "<<BCatchArith:B\d+>>" "<<BCatchAll:B\d+>>"
## CHECK: name "<<BCatchArith>>"
-## CHECK: predecessors "<<BExit1Enter2>>" "<<BExit2Enter3>>"
+## CHECK: predecessors "<<BEnter2>>" "<<BExit2>>"
## CHECK: successors "<<BReturn>>"
## CHECK: flags "catch_block"
## CHECK: StoreLocal [v0,<<Minus1>>]
## CHECK: name "<<BCatchAll>>"
-## CHECK: predecessors "<<BEnter1>>" "<<BExit1Enter2>>" "<<BExit2Enter3>>" "<<BExit3>>"
+## CHECK: predecessors "<<BEnter1>>" "<<BExit1>>" "<<BEnter2>>" "<<BExit2>>" "<<BEnter3>>" "<<BExit3>>"
## CHECK: successors "<<BReturn>>"
## CHECK: flags "catch_block"
## CHECK: StoreLocal [v0,<<Minus2>>]
@@ -480,25 +492,37 @@
## CHECK: predecessors "B0"
## CHECK: successors "<<BTry1>>"
## CHECK: xhandlers "<<BCatchAll>>"
-## CHECK: TryBoundary is_entry:true is_exit:false
+## CHECK: TryBoundary kind:entry
-## CHECK: name "<<BExit1Enter2>>"
+## CHECK: name "<<BExit1>>"
## CHECK: predecessors "<<BTry1>>"
-## CHECK: successors "<<BTry2>>"
-## CHECK: xhandlers "<<BCatchAll>>" "<<BCatchArith>>"
-## CHECK: TryBoundary is_entry:true is_exit:true
+## CHECK: successors "<<BEnter2>>"
+## CHECK: xhandlers "<<BCatchAll>>"
+## CHECK: TryBoundary kind:exit
-## CHECK: name "<<BExit2Enter3>>"
-## CHECK: predecessors "<<BTry2>>"
-## CHECK: successors "<<BTry3>>"
+## CHECK: name "<<BEnter2>>"
+## CHECK: predecessors "<<BExit1>>"
+## CHECK: successors "<<BTry2>>"
## CHECK: xhandlers "<<BCatchArith>>" "<<BCatchAll>>"
-## CHECK: TryBoundary is_entry:true is_exit:true
+## CHECK: TryBoundary kind:entry
+
+## CHECK: name "<<BExit2>>"
+## CHECK: predecessors "<<BTry2>>"
+## CHECK: successors "<<BEnter3>>"
+## CHECK: xhandlers "<<BCatchArith>>" "<<BCatchAll>>"
+## CHECK: TryBoundary kind:exit
+
+## CHECK: name "<<BEnter3>>"
+## CHECK: predecessors "<<BExit2>>"
+## CHECK: successors "<<BTry3>>"
+## CHECK: xhandlers "<<BCatchAll>>"
+## CHECK: TryBoundary kind:entry
## CHECK: name "<<BExit3>>"
## CHECK: predecessors "<<BTry3>>"
## CHECK: successors "<<BReturn>>"
## CHECK: xhandlers "<<BCatchAll>>"
-## CHECK: TryBoundary is_entry:false is_exit:true
+## CHECK: TryBoundary kind:exit
.method public static testNestedTry(IIII)I
.registers 4
@@ -562,25 +586,25 @@
## CHECK: predecessors "B0"
## CHECK: successors "<<BTry1>>"
## CHECK: xhandlers "<<BCatch>>"
-## CHECK: TryBoundary is_entry:true is_exit:false
+## CHECK: TryBoundary kind:entry
## CHECK: name "<<BExitTry1>>"
## CHECK: predecessors "<<BTry1>>"
## CHECK: successors "<<BOutside>>"
## CHECK: xhandlers "<<BCatch>>"
-## CHECK: TryBoundary is_entry:false is_exit:true
+## CHECK: TryBoundary kind:exit
## CHECK: name "<<BEnterTry2>>"
## CHECK: predecessors "<<BOutside>>"
## CHECK: successors "<<BTry2>>"
## CHECK: xhandlers "<<BCatch>>"
-## CHECK: TryBoundary is_entry:true is_exit:false
+## CHECK: TryBoundary kind:entry
## CHECK: name "<<BExitTry2>>"
## CHECK: predecessors "<<BTry2>>"
## CHECK: successors "<<BReturn>>"
## CHECK: xhandlers "<<BCatch>>"
-## CHECK: TryBoundary is_entry:false is_exit:true
+## CHECK: TryBoundary kind:exit
.method public static testIncontinuousTry(IIII)I
.registers 4
@@ -630,13 +654,13 @@
## CHECK: predecessors "B0"
## CHECK: successors "<<BTry>>"
## CHECK: xhandlers "<<BCatch>>"
-## CHECK: TryBoundary is_entry:true is_exit:false
+## CHECK: TryBoundary kind:entry
## CHECK: name "<<BExitTry>>"
## CHECK: predecessors "<<BTry>>"
## CHECK: successors "<<BExit>>"
## CHECK: xhandlers "<<BCatch>>"
-## CHECK: TryBoundary is_entry:false is_exit:true
+## CHECK: TryBoundary kind:exit
## CHECK: name "<<BExit>>"
## CHECK: predecessors "<<BExitTry>>" "<<BCatch>>"
@@ -660,28 +684,32 @@
## CHECK-START: int Builder.testCatchLoop(int, int, int) builder (after)
## CHECK: name "B0"
-## CHECK: successors "<<BEnterTry:B\d+>>"
+## CHECK: successors "<<BCatch:B\d+>>"
-## CHECK: name "<<BTry:B\d+>>"
-## CHECK: predecessors "<<BEnterTry>>" "<<BEnterTry>>" "<<BExitTry:B\d+>>"
-## CHECK: successors "<<BExitTry>>"
+## CHECK: name "<<BCatch>>"
+## CHECK: predecessors "B0" "<<BEnterTry:B\d+>>" "<<BExitTry:B\d+>>"
+## CHECK: successors "<<BEnterTry>>"
## CHECK: flags "catch_block"
-## CHECK: Div
## CHECK: name "<<BReturn:B\d+>>"
## CHECK: predecessors "<<BExitTry>>"
+## CHECK: name "<<BTry:B\d+>>"
+## CHECK: predecessors "<<BEnterTry>>"
+## CHECK: successors "<<BExitTry>>"
+## CHECK: Div
+
## CHECK: name "<<BEnterTry>>"
-## CHECK: predecessors "B0"
+## CHECK: predecessors "<<BCatch>>"
## CHECK: successors "<<BTry>>"
-## CHECK: xhandlers "<<BTry>>"
-## CHECK: TryBoundary is_entry:true is_exit:false
+## CHECK: xhandlers "<<BCatch>>"
+## CHECK: TryBoundary kind:entry
## CHECK: name "<<BExitTry>>"
## CHECK: predecessors "<<BTry>>"
## CHECK: successors "<<BReturn>>"
-## CHECK: xhandlers "<<BTry>>"
-## CHECK: TryBoundary is_entry:false is_exit:true
+## CHECK: xhandlers "<<BCatch>>"
+## CHECK: TryBoundary kind:exit
.method public static testCatchLoop(III)I
.registers 4
@@ -702,33 +730,49 @@
## CHECK-START: int Builder.testHandlerEdge1(int, int, int) builder (after)
## CHECK: name "B0"
-## CHECK: successors "<<BEnterTry:B\d+>>"
+## CHECK: successors "<<BEnterTry1:B\d+>>"
-## CHECK: name "<<BTry:B\d+>>"
-## CHECK: predecessors "<<BEnterTry>>"
-## CHECK: successors "<<BCatch:B\d+>>"
+## CHECK: name "<<BTry1:B\d+>>"
+## CHECK: predecessors "<<BEnterTry1>>"
+## CHECK: successors "<<BExitTry1:B\d+>>"
## CHECK: Div
-## CHECK: name "<<BCatch>>"
-## CHECK: predecessors "<<BTry>>" "<<BEnterTry>>" "<<BExitTry:B\d+>>"
-## CHECK: successors "<<BExitTry>>"
+## CHECK: name "<<BCatch:B\d+>>"
+## CHECK: predecessors "<<BExitTry1>>" "<<BEnterTry1>>" "<<BExitTry1>>" "<<BEnterTry2:B\d+>>" "<<BExitTry2:B\d+>>"
+## CHECK: successors "<<BEnterTry2>>"
## CHECK: flags "catch_block"
-## CHECK: Div
## CHECK: name "<<BReturn:B\d+>>"
-## CHECK: predecessors "<<BExitTry>>"
+## CHECK: predecessors "<<BExitTry2>>"
-## CHECK: name "<<BEnterTry>>"
+## CHECK: name "<<BEnterTry1>>"
## CHECK: predecessors "B0"
-## CHECK: successors "<<BTry>>"
+## CHECK: successors "<<BTry1>>"
## CHECK: xhandlers "<<BCatch>>"
-## CHECK: TryBoundary is_entry:true is_exit:false
+## CHECK: TryBoundary kind:entry
-## CHECK: name "<<BExitTry>>"
+## CHECK: name "<<BExitTry1>>"
+## CHECK: predecessors "<<BTry1>>"
+## CHECK: successors "<<BCatch>>"
+## CHECK: xhandlers "<<BCatch>>"
+## CHECK: TryBoundary kind:exit
+
+## CHECK: name "<<BTry2:B\d+>>"
+## CHECK: predecessors "<<BEnterTry2>>"
+## CHECK: successors "<<BExitTry2>>"
+## CHECK: Div
+
+## CHECK: name "<<BEnterTry2>>"
## CHECK: predecessors "<<BCatch>>"
+## CHECK: successors "<<BTry2>>"
+## CHECK: xhandlers "<<BCatch>>"
+## CHECK: TryBoundary kind:entry
+
+## CHECK: name "<<BExitTry2>>"
+## CHECK: predecessors "<<BTry2>>"
## CHECK: successors "<<BReturn>>"
## CHECK: xhandlers "<<BCatch>>"
-## CHECK: TryBoundary is_entry:false is_exit:true
+## CHECK: TryBoundary kind:exit
.method public static testHandlerEdge1(III)I
.registers 4
@@ -750,41 +794,55 @@
## CHECK-START: int Builder.testHandlerEdge2(int, int, int) builder (after)
## CHECK: name "B0"
+## CHECK: successors "<<BCatch1:B\d+>>"
+
+## CHECK: name "<<BCatch1>>"
+## CHECK: predecessors "B0" "<<BEnter2:B\d+>>" "<<BExit2:B\d+>>"
## CHECK: successors "<<BEnter1:B\d+>>"
-
-## CHECK: name "<<BTry1:B\d+>>"
-## CHECK: predecessors "<<BEnter1>>" "<<BExit1Enter2:B\d+>>" "<<BExit2:B\d+>>"
-## CHECK: successors "<<BExit1Enter2>>"
## CHECK: flags "catch_block"
-## CHECK: Div
-## CHECK: name "<<BTry2:B\d+>>"
-## CHECK: predecessors "<<BExit1Enter2>>" "<<BEnter1>>" "<<BExit1Enter2>>"
-## CHECK: successors "<<BExit2>>"
+## CHECK: name "<<BCatch2:B\d+>>"
+## CHECK: predecessors "<<BExit1:B\d+>>" "<<BEnter1>>" "<<BExit1>>"
+## CHECK: successors "<<BEnter2>>"
## CHECK: flags "catch_block"
-## CHECK: Div
## CHECK: name "<<BReturn:B\d+>>"
## CHECK: predecessors "<<BExit2>>"
## CHECK: Return
-## CHECK: name "<<BEnter1>>"
-## CHECK: predecessors "B0"
-## CHECK: successors "<<BTry1>>"
-## CHECK: xhandlers "<<BTry2>>"
-## CHECK: TryBoundary is_entry:true is_exit:false
+## CHECK: name "<<BTry1:B\d+>>"
+## CHECK: predecessors "<<BEnter1>>"
+## CHECK: successors "<<BExit1>>"
+## CHECK: Div
-## CHECK: name "<<BExit1Enter2>>"
+## CHECK: name "<<BEnter1>>"
+## CHECK: predecessors "<<BCatch1>>"
+## CHECK: successors "<<BTry1>>"
+## CHECK: xhandlers "<<BCatch2>>"
+## CHECK: TryBoundary kind:entry
+
+## CHECK: name "<<BExit1>>"
## CHECK: predecessors "<<BTry1>>"
+## CHECK: successors "<<BCatch2>>"
+## CHECK: xhandlers "<<BCatch2>>"
+## CHECK: TryBoundary kind:exit
+
+## CHECK: name "<<BTry2:B\d+>>"
+## CHECK: predecessors "<<BEnter2>>"
+## CHECK: successors "<<BExit2>>"
+## CHECK: Div
+
+## CHECK: name "<<BEnter2>>"
+## CHECK: predecessors "<<BCatch2>>"
## CHECK: successors "<<BTry2>>"
-## CHECK: xhandlers "<<BTry2>>" "<<BTry1>>"
-## CHECK: TryBoundary is_entry:true is_exit:true
+## CHECK: xhandlers "<<BCatch1>>"
+## CHECK: TryBoundary kind:entry
## CHECK: name "<<BExit2>>"
## CHECK: predecessors "<<BTry2>>"
## CHECK: successors "<<BReturn>>"
-## CHECK: xhandlers "<<BTry1>>"
-## CHECK: TryBoundary is_entry:false is_exit:true
+## CHECK: xhandlers "<<BCatch1>>"
+## CHECK: TryBoundary kind:exit
.method public static testHandlerEdge2(III)I
.registers 4
diff --git a/test/521-checker-array-set-null/expected.txt b/test/521-checker-array-set-null/expected.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/521-checker-array-set-null/expected.txt
diff --git a/test/521-checker-array-set-null/info.txt b/test/521-checker-array-set-null/info.txt
new file mode 100644
index 0000000..ec2ba35
--- /dev/null
+++ b/test/521-checker-array-set-null/info.txt
@@ -0,0 +1,2 @@
+Checker test for optimizing that checks whether our
+optimizations to remove type checks on array set operations work.
diff --git a/test/521-checker-array-set-null/src/Main.java b/test/521-checker-array-set-null/src/Main.java
new file mode 100644
index 0000000..74bb73f
--- /dev/null
+++ b/test/521-checker-array-set-null/src/Main.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2015 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) {
+ testWithNull(new Object[2]);
+ testWithUnknown(new Object[2], new Object());
+ testWithSame(new Object[2]);
+ }
+
+ /// CHECK-START: void Main.testWithNull(java.lang.Object[]) disassembly (after)
+ /// CHECK-NOT: pAputObject
+ public static void testWithNull(Object[] o) {
+ o[0] = null;
+ }
+
+ /// CHECK-START: void Main.testWithUnknown(java.lang.Object[], java.lang.Object) disassembly (after)
+ /// CHECK: pAputObject
+ public static void testWithUnknown(Object[] o, Object obj) {
+ o[0] = obj;
+ }
+
+ /// CHECK-START: void Main.testWithSame(java.lang.Object[]) disassembly (after)
+ /// CHECK-NOT: pAputObject
+ public static void testWithSame(Object[] o) {
+ o[0] = o[1];
+ }
+}
diff --git a/test/521-regression-integer-field-set/expected.txt b/test/521-regression-integer-field-set/expected.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/521-regression-integer-field-set/expected.txt
diff --git a/test/521-regression-integer-field-set/info.txt b/test/521-regression-integer-field-set/info.txt
new file mode 100644
index 0000000..62f7e3d
--- /dev/null
+++ b/test/521-regression-integer-field-set/info.txt
@@ -0,0 +1,3 @@
+Regression test for Optimizing's x86-64 code generator, where moving a
+32-bit immediate (integer or reference) into a field used to generate
+a `movw` instruction instead of a `movl` instruction.
diff --git a/test/521-regression-integer-field-set/src/Main.java b/test/521-regression-integer-field-set/src/Main.java
new file mode 100644
index 0000000..9924e09
--- /dev/null
+++ b/test/521-regression-integer-field-set/src/Main.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+
+class Main {
+ public static void assertIntEquals(int expected, int result) {
+ if (expected != result) {
+ throw new Error("Expected: " + expected + ", found: " + result);
+ }
+ }
+
+ public static void main(String[] args) {
+ Main m = new Main();
+
+ m.$noinline$SetInstanceField();
+ assertIntEquals(123456, m.i);
+
+ $noinline$SetStaticField();
+ assertIntEquals(456789, s);
+ }
+
+ private static boolean doThrow = false;
+
+ private void $noinline$SetInstanceField() {
+ if (doThrow) {
+ // Try defeating inlining.
+ throw new Error();
+ }
+
+ // Set a value than does not fit in a 16-bit (signed) integer.
+ i = 123456;
+ }
+
+ private static void $noinline$SetStaticField() {
+ if (doThrow) {
+ // Try defeating inlining.
+ throw new Error();
+ }
+
+ // Set a value than does not fit in a 16-bit (signed) integer.
+ s = 456789;
+ }
+
+ private int i = 0;
+ private static int s = 0;
+}
diff --git a/test/802-deoptimization/src/DeoptimizationController.java b/test/802-deoptimization/src/DeoptimizationController.java
index c926669..d6e662d 100644
--- a/test/802-deoptimization/src/DeoptimizationController.java
+++ b/test/802-deoptimization/src/DeoptimizationController.java
@@ -22,24 +22,27 @@
* Controls deoptimization using dalvik.system.VMDebug class.
*/
public class DeoptimizationController {
+ private static final String TEMP_FILE_NAME_PREFIX = "test";
+ private static final String TEMP_FILE_NAME_SUFFIX = ".trace";
+
private static File createTempFile() throws Exception {
try {
- return File.createTempFile("test", ".trace");
+ return File.createTempFile(TEMP_FILE_NAME_PREFIX, TEMP_FILE_NAME_SUFFIX);
} catch (IOException e) {
System.setProperty("java.io.tmpdir", "/data/local/tmp");
try {
- return File.createTempFile("test", ".trace");
+ return File.createTempFile(TEMP_FILE_NAME_PREFIX, TEMP_FILE_NAME_SUFFIX);
} catch (IOException e2) {
System.setProperty("java.io.tmpdir", "/sdcard");
- return File.createTempFile("test", ".trace");
+ return File.createTempFile(TEMP_FILE_NAME_PREFIX, TEMP_FILE_NAME_SUFFIX);
}
}
}
public static void startDeoptimization() {
+ File tempFile = null;
try {
- File tempFile = createTempFile();
- tempFile.deleteOnExit();
+ tempFile = createTempFile();
String tempFileName = tempFile.getPath();
VMDebug.startMethodTracing(tempFileName, 0, 0, false, 1000);
@@ -48,6 +51,10 @@
}
} catch (Exception exc) {
exc.printStackTrace(System.err);
+ } finally {
+ if (tempFile != null) {
+ tempFile.delete();
+ }
}
}
diff --git a/test/Android.run-test.mk b/test/Android.run-test.mk
index 6c2ce62..5b5c368 100644
--- a/test/Android.run-test.mk
+++ b/test/Android.run-test.mk
@@ -233,7 +233,10 @@
TEST_ART_BROKEN_NO_RELOCATE_TESTS :=
# Tests that are broken with GC stress.
-TEST_ART_BROKEN_GCSTRESS_RUN_TESTS :=
+# 137-cfi needs to unwind a second forked process. We're using a primitive sleep to wait till we
+# hope the second process got into the expected state. The slowness of gcstress makes this bad.
+TEST_ART_BROKEN_GCSTRESS_RUN_TESTS := \
+ 137-cfi
ifneq (,$(filter gcstress,$(GC_TYPES)))
ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,$(TARGET_TYPES),$(RUN_TYPES),$(PREBUILD_TYPES), \
diff --git a/test/run-test b/test/run-test
index 995d30f..ffa25eb 100755
--- a/test/run-test
+++ b/test/run-test
@@ -308,7 +308,7 @@
run_args="${run_args} --runtime-option -Xgc:preverify_rosalloc --runtime-option -Xgc:postverify_rosalloc"
fi
if [ "$gc_stress" = "true" ]; then
- run_args="${run_args} --runtime-option -Xgc:SS --runtime-option -Xms2m --runtime-option -Xmx2m"
+ run_args="${run_args} --runtime-option -Xgc:SS,gcstress --runtime-option -Xms2m --runtime-option -Xmx16m"
fi
if [ "$trace" = "true" ]; then
run_args="${run_args} --runtime-option -Xmethod-trace --runtime-option -Xmethod-trace-file-size:2000000"
diff --git a/tools/symbolize.sh b/tools/symbolize.sh
index 0168e7d..7365a9b 100755
--- a/tools/symbolize.sh
+++ b/tools/symbolize.sh
@@ -37,30 +37,23 @@
exit 0
fi
fi
- adb pull /data/dalvik-cache/$1/$2 /tmp || exit 1
- mkdir -p $OUT/symbols/data/dalvik-cache/$1
- oatdump --symbolize=/tmp/$2 --output=$OUT/symbols/data/dalvik-cache/$1/$2
+ adb pull $1/$2 /tmp || exit 1
+ mkdir -p $OUT/symbols/$1
+ oatdump --symbolize=/tmp/$2 --output=$OUT/symbols/$1/$2
}
-# adb shell ls seems to output in DOS format (CRLF), which messes up scripting
-function adbls() {
- adb shell ls $@ | sed 's/\r$//'
+# adb shell find seems to output in DOS format (CRLF), which messes up scripting
+function adbshellstrip() {
+ adb shell $@ | sed 's/\r$//'
}
-# Check for all ISA directories on device.
+# Search in all of /data on device.
function all() {
- DIRS=$(adbls /data/dalvik-cache/)
- for DIR in $DIRS ; do
- case $DIR in
- arm|arm64|mips|mips64|x86|x86_64)
- FILES=$(adbls /data/dalvik-cache/$DIR/*.oat /data/dalvik-cache/$DIR/*.dex)
- for FILE in $FILES ; do
- # Cannot use basename as the file doesn't exist.
- NAME=$(echo $FILE | sed -e 's/.*\///')
- one $DIR $NAME
- done
- ;;
- esac
+ FILES=$(adbshellstrip find /data -name "'*.oat'" -o -name "'*.dex'" -o -name "'*.odex'")
+ for FILE in $FILES ; do
+ DIR=$(dirname $FILE)
+ NAME=$(basename $FILE)
+ one $DIR $NAME
done
}