Merge "Support callee save floating point registers on x64."
diff --git a/compiler/dex/quick/gen_invoke.cc b/compiler/dex/quick/gen_invoke.cc
index 2a6dfef..d5889f5 100755
--- a/compiler/dex/quick/gen_invoke.cc
+++ b/compiler/dex/quick/gen_invoke.cc
@@ -1048,9 +1048,13 @@
// TODO - add Mips implementation.
return false;
}
+ RegLocation rl_dest = IsWide(size) ? InlineTargetWide(info) : InlineTarget(info); // result reg
+ if (rl_dest.s_reg_low == INVALID_SREG) {
+ // Result is unused, the code is dead. Inlining successful, no code generated.
+ return true;
+ }
RegLocation rl_src_i = info->args[0];
RegLocation rl_i = IsWide(size) ? LoadValueWide(rl_src_i, kCoreReg) : LoadValue(rl_src_i, kCoreReg);
- RegLocation rl_dest = IsWide(size) ? InlineTargetWide(info) : InlineTarget(info); // result reg
RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
if (IsWide(size)) {
if (cu_->instruction_set == kArm64 || cu_->instruction_set == kX86_64) {
@@ -1080,9 +1084,13 @@
}
bool Mir2Lir::GenInlinedAbsInt(CallInfo* info) {
+ RegLocation rl_dest = InlineTarget(info);
+ if (rl_dest.s_reg_low == INVALID_SREG) {
+ // Result is unused, the code is dead. Inlining successful, no code generated.
+ return true;
+ }
RegLocation rl_src = info->args[0];
rl_src = LoadValue(rl_src, kCoreReg);
- RegLocation rl_dest = InlineTarget(info);
RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
RegStorage sign_reg = AllocTemp();
// abs(x) = y<=x>>31, (x+y)^y.
@@ -1094,9 +1102,13 @@
}
bool Mir2Lir::GenInlinedAbsLong(CallInfo* info) {
+ RegLocation rl_dest = InlineTargetWide(info);
+ if (rl_dest.s_reg_low == INVALID_SREG) {
+ // Result is unused, the code is dead. Inlining successful, no code generated.
+ return true;
+ }
RegLocation rl_src = info->args[0];
rl_src = LoadValueWide(rl_src, kCoreReg);
- RegLocation rl_dest = InlineTargetWide(info);
RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
// If on x86 or if we would clobber a register needed later, just copy the source first.
@@ -1171,8 +1183,12 @@
// TODO - add Mips implementation
return false;
}
- RegLocation rl_src = info->args[0];
RegLocation rl_dest = InlineTarget(info);
+ if (rl_dest.s_reg_low == INVALID_SREG) {
+ // Result is unused, the code is dead. Inlining successful, no code generated.
+ return true;
+ }
+ RegLocation rl_src = info->args[0];
StoreValue(rl_dest, rl_src);
return true;
}
@@ -1182,8 +1198,12 @@
// TODO - add Mips implementation
return false;
}
- RegLocation rl_src = info->args[0];
RegLocation rl_dest = InlineTargetWide(info);
+ if (rl_dest.s_reg_low == INVALID_SREG) {
+ // Result is unused, the code is dead. Inlining successful, no code generated.
+ return true;
+ }
+ RegLocation rl_src = info->args[0];
StoreValueWide(rl_dest, rl_src);
return true;
}
diff --git a/compiler/dex/quick/x86/fp_x86.cc b/compiler/dex/quick/x86/fp_x86.cc
index 4825db6..89c5648 100755
--- a/compiler/dex/quick/x86/fp_x86.cc
+++ b/compiler/dex/quick/x86/fp_x86.cc
@@ -599,8 +599,12 @@
}
bool X86Mir2Lir::GenInlinedSqrt(CallInfo* info) {
- RegLocation rl_src = info->args[0];
RegLocation rl_dest = InlineTargetWide(info); // double place for result
+ if (rl_dest.s_reg_low == INVALID_SREG) {
+ // Result is unused, the code is dead. Inlining successful, no code generated.
+ return true;
+ }
+ RegLocation rl_src = info->args[0];
rl_src = LoadValueWide(rl_src, kFPReg);
RegLocation rl_result = EvalLoc(rl_dest, kFPReg, true);
NewLIR2(kX86SqrtsdRR, rl_result.reg.GetReg(), rl_src.reg.GetReg());
@@ -722,9 +726,13 @@
bool X86Mir2Lir::GenInlinedMinMaxFP(CallInfo* info, bool is_min, bool is_double) {
if (is_double) {
+ RegLocation rl_dest = InlineTargetWide(info);
+ if (rl_dest.s_reg_low == INVALID_SREG) {
+ // Result is unused, the code is dead. Inlining successful, no code generated.
+ return true;
+ }
RegLocation rl_src1 = LoadValueWide(info->args[0], kFPReg);
RegLocation rl_src2 = LoadValueWide(info->args[2], kFPReg);
- RegLocation rl_dest = InlineTargetWide(info);
RegLocation rl_result = EvalLocWide(rl_dest, kFPReg, true);
// Avoid src2 corruption by OpRegCopyWide.
@@ -775,9 +783,13 @@
branch_exit_equal->target = NewLIR0(kPseudoTargetLabel);
StoreValueWide(rl_dest, rl_result);
} else {
+ RegLocation rl_dest = InlineTarget(info);
+ if (rl_dest.s_reg_low == INVALID_SREG) {
+ // Result is unused, the code is dead. Inlining successful, no code generated.
+ return true;
+ }
RegLocation rl_src1 = LoadValue(info->args[0], kFPReg);
RegLocation rl_src2 = LoadValue(info->args[1], kFPReg);
- RegLocation rl_dest = InlineTarget(info);
RegLocation rl_result = EvalLoc(rl_dest, kFPReg, true);
// Avoid src2 corruption by OpRegCopyWide.
diff --git a/compiler/dex/quick/x86/int_x86.cc b/compiler/dex/quick/x86/int_x86.cc
index ba9c611..03156dc 100755
--- a/compiler/dex/quick/x86/int_x86.cc
+++ b/compiler/dex/quick/x86/int_x86.cc
@@ -948,12 +948,16 @@
}
// Get the two arguments to the invoke and place them in GP registers.
+ RegLocation rl_dest = (is_long) ? InlineTargetWide(info) : InlineTarget(info);
+ if (rl_dest.s_reg_low == INVALID_SREG) {
+ // Result is unused, the code is dead. Inlining successful, no code generated.
+ return true;
+ }
RegLocation rl_src1 = info->args[0];
RegLocation rl_src2 = (is_long) ? info->args[2] : info->args[1];
rl_src1 = (is_long) ? LoadValueWide(rl_src1, kCoreReg) : LoadValue(rl_src1, kCoreReg);
rl_src2 = (is_long) ? LoadValueWide(rl_src2, kCoreReg) : LoadValue(rl_src2, kCoreReg);
- RegLocation rl_dest = (is_long) ? InlineTargetWide(info) : InlineTarget(info);
RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
/*
@@ -988,6 +992,11 @@
}
bool X86Mir2Lir::GenInlinedPeek(CallInfo* info, OpSize size) {
+ RegLocation rl_dest = size == k64 ? InlineTargetWide(info) : InlineTarget(info);
+ if (rl_dest.s_reg_low == INVALID_SREG) {
+ // Result is unused, the code is dead. Inlining successful, no code generated.
+ return true;
+ }
RegLocation rl_src_address = info->args[0]; // long address
RegLocation rl_address;
if (!cu_->target64) {
@@ -996,7 +1005,6 @@
} else {
rl_address = LoadValueWide(rl_src_address, kCoreReg);
}
- RegLocation rl_dest = size == k64 ? InlineTargetWide(info) : InlineTarget(info);
RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
// Unaligned access is allowed on x86.
LoadBaseDisp(rl_address.reg, 0, rl_result.reg, size, kNotVolatile);
@@ -1238,10 +1246,14 @@
}
bool X86Mir2Lir::GenInlinedReverseBits(CallInfo* info, OpSize size) {
+ RegLocation rl_dest = (size == k64) ? InlineTargetWide(info) : InlineTarget(info);
+ if (rl_dest.s_reg_low == INVALID_SREG) {
+ // Result is unused, the code is dead. Inlining successful, no code generated.
+ return true;
+ }
RegLocation rl_src_i = info->args[0];
RegLocation rl_i = (size == k64) ? LoadValueWide(rl_src_i, kCoreReg)
: LoadValue(rl_src_i, kCoreReg);
- RegLocation rl_dest = (size == k64) ? InlineTargetWide(info) : InlineTarget(info);
RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
if (size == k64) {
if (cu_->instruction_set == kX86_64) {
diff --git a/compiler/optimizing/graph_checker.cc b/compiler/optimizing/graph_checker.cc
index 291b14c..4d74c4e 100644
--- a/compiler/optimizing/graph_checker.cc
+++ b/compiler/optimizing/graph_checker.cc
@@ -17,10 +17,10 @@
#include "graph_checker.h"
#include <map>
-#include <sstream>
#include <string>
#include "base/bit_vector-inl.h"
+#include "base/stringprintf.h"
namespace art {
@@ -45,15 +45,11 @@
}
}
if (p_count_in_block_predecessors != block_count_in_p_successors) {
- std::stringstream error;
- error << "Block " << block->GetBlockId()
- << " lists " << p_count_in_block_predecessors
- << " occurrences of block " << p->GetBlockId()
- << " in its predecessors, whereas block " << p->GetBlockId()
- << " lists " << block_count_in_p_successors
- << " occurrences of block " << block->GetBlockId()
- << " in its successors.";
- errors_.push_back(error.str());
+ AddError(StringPrintf(
+ "Block %d lists %zu occurrences of block %d in its predecessors, whereas "
+ "block %d lists %zu occurrences of block %d in its successors.",
+ block->GetBlockId(), p_count_in_block_predecessors, p->GetBlockId(),
+ p->GetBlockId(), block_count_in_p_successors, block->GetBlockId()));
}
}
@@ -75,35 +71,27 @@
}
}
if (s_count_in_block_successors != block_count_in_s_predecessors) {
- std::stringstream error;
- error << "Block " << block->GetBlockId()
- << " lists " << s_count_in_block_successors
- << " occurrences of block " << s->GetBlockId()
- << " in its successors, whereas block " << s->GetBlockId()
- << " lists " << block_count_in_s_predecessors
- << " occurrences of block " << block->GetBlockId()
- << " in its predecessors.";
- errors_.push_back(error.str());
+ AddError(StringPrintf(
+ "Block %d lists %zu occurrences of block %d in its successors, whereas "
+ "block %d lists %zu occurrences of block %d in its predecessors.",
+ block->GetBlockId(), s_count_in_block_successors, s->GetBlockId(),
+ s->GetBlockId(), block_count_in_s_predecessors, block->GetBlockId()));
}
}
// Ensure `block` ends with a branch instruction.
HInstruction* last_inst = block->GetLastInstruction();
if (last_inst == nullptr || !last_inst->IsControlFlow()) {
- std::stringstream error;
- error << "Block " << block->GetBlockId()
- << " does not end with a branch instruction.";
- errors_.push_back(error.str());
+ AddError(StringPrintf("Block %d does not end with a branch instruction.",
+ block->GetBlockId()));
}
// Visit this block's list of phis.
for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
// Ensure this block's list of phis contains only phis.
if (!it.Current()->IsPhi()) {
- std::stringstream error;
- error << "Block " << current_block_->GetBlockId()
- << " has a non-phi in its phi list.";
- errors_.push_back(error.str());
+ AddError(StringPrintf("Block %d has a non-phi in its phi list.",
+ current_block_->GetBlockId()));
}
it.Current()->Accept(this);
}
@@ -113,10 +101,8 @@
it.Advance()) {
// Ensure this block's list of instructions does not contains phis.
if (it.Current()->IsPhi()) {
- std::stringstream error;
- error << "Block " << current_block_->GetBlockId()
- << " has a phi in its non-phi list.";
- errors_.push_back(error.str());
+ AddError(StringPrintf("Block %d has a phi in its non-phi list.",
+ current_block_->GetBlockId()));
}
it.Current()->Accept(this);
}
@@ -124,30 +110,24 @@
void GraphChecker::VisitInstruction(HInstruction* instruction) {
if (seen_ids_.IsBitSet(instruction->GetId())) {
- std::stringstream error;
- error << "Duplicate id in graph " << instruction->GetId() << ".";
- errors_.push_back(error.str());
+ AddError(StringPrintf("Instruction id %d is duplicate in graph.",
+ instruction->GetId()));
} else {
seen_ids_.SetBit(instruction->GetId());
}
// Ensure `instruction` is associated with `current_block_`.
- if (instruction->GetBlock() != current_block_) {
- std::stringstream error;
- if (instruction->IsPhi()) {
- error << "Phi ";
- } else {
- error << "Instruction ";
- }
- error << instruction->GetId() << " in block "
- << current_block_->GetBlockId();
- if (instruction->GetBlock() != nullptr) {
- error << " associated with block "
- << instruction->GetBlock()->GetBlockId() << ".";
- } else {
- error << " not associated with any block.";
- }
- errors_.push_back(error.str());
+ if (instruction->GetBlock() == nullptr) {
+ AddError(StringPrintf("%s %d in block %d not associated with any block.",
+ instruction->IsPhi() ? "Phi" : "Instruction",
+ instruction->GetId(),
+ current_block_->GetBlockId()));
+ } else if (instruction->GetBlock() != current_block_) {
+ AddError(StringPrintf("%s %d in block %d associated with block %d.",
+ instruction->IsPhi() ? "Phi" : "Instruction",
+ instruction->GetId(),
+ current_block_->GetBlockId(),
+ instruction->GetBlock()->GetBlockId()));
}
// Ensure the inputs of `instruction` are defined in a block of the graph.
@@ -158,11 +138,10 @@
? input->GetBlock()->GetPhis()
: input->GetBlock()->GetInstructions();
if (!list.Contains(input)) {
- std::stringstream error;
- error << "Input " << input->GetId()
- << " of instruction " << instruction->GetId()
- << " is not defined in a basic block of the control-flow graph.";
- errors_.push_back(error.str());
+ AddError(StringPrintf("Input %d of instruction %d is not defined "
+ "in a basic block of the control-flow graph.",
+ input->GetId(),
+ instruction->GetId()));
}
}
@@ -174,11 +153,10 @@
? use->GetBlock()->GetPhis()
: use->GetBlock()->GetInstructions();
if (!list.Contains(use)) {
- std::stringstream error;
- error << "User " << use->GetId()
- << " of instruction " << instruction->GetId()
- << " is not defined in a basic block of the control-flow graph.";
- errors_.push_back(error.str());
+ AddError(StringPrintf("User %d of instruction %d is not defined "
+ "in a basic block of the control-flow graph.",
+ use->GetId(),
+ instruction->GetId()));
}
}
}
@@ -193,10 +171,9 @@
for (size_t j = 0; j < block->GetSuccessors().Size(); ++j) {
HBasicBlock* successor = block->GetSuccessors().Get(j);
if (successor->GetPredecessors().Size() > 1) {
- std::stringstream error;
- error << "Critical edge between blocks " << block->GetBlockId()
- << " and " << successor->GetBlockId() << ".";
- errors_.push_back(error.str());
+ AddError(StringPrintf("Critical edge between blocks %d and %d.",
+ block->GetBlockId(),
+ successor->GetBlockId()));
}
}
}
@@ -212,47 +189,52 @@
// Ensure the pre-header block is first in the list of
// predecessors of a loop header.
if (!loop_header->IsLoopPreHeaderFirstPredecessor()) {
- std::stringstream error;
- error << "Loop pre-header is not the first predecessor of the loop header "
- << id << ".";
- errors_.push_back(error.str());
+ AddError(StringPrintf(
+ "Loop pre-header is not the first predecessor of the loop header %d.",
+ id));
}
// Ensure the loop header has only two predecessors and that only the
// second one is a back edge.
- if (loop_header->GetPredecessors().Size() < 2) {
- std::stringstream error;
- error << "Loop header " << id << " has less than two predecessors.";
- errors_.push_back(error.str());
- } else if (loop_header->GetPredecessors().Size() > 2) {
- std::stringstream error;
- error << "Loop header " << id << " has more than two predecessors.";
- errors_.push_back(error.str());
+ size_t num_preds = loop_header->GetPredecessors().Size();
+ if (num_preds < 2) {
+ AddError(StringPrintf(
+ "Loop header %d has less than two predecessors: %zu.",
+ id,
+ num_preds));
+ } else if (num_preds > 2) {
+ AddError(StringPrintf(
+ "Loop header %d has more than two predecessors: %zu.",
+ id,
+ num_preds));
} else {
HLoopInformation* loop_information = loop_header->GetLoopInformation();
HBasicBlock* first_predecessor = loop_header->GetPredecessors().Get(0);
if (loop_information->IsBackEdge(first_predecessor)) {
- std::stringstream error;
- error << "First predecessor of loop header " << id << " is a back edge.";
- errors_.push_back(error.str());
+ AddError(StringPrintf(
+ "First predecessor of loop header %d is a back edge.",
+ id));
}
HBasicBlock* second_predecessor = loop_header->GetPredecessors().Get(1);
if (!loop_information->IsBackEdge(second_predecessor)) {
- std::stringstream error;
- error << "Second predecessor of loop header " << id
- << " is not a back edge.";
- errors_.push_back(error.str());
+ AddError(StringPrintf(
+ "Second predecessor of loop header %d is not a back edge.",
+ id));
}
}
// Ensure there is only one back edge per loop.
size_t num_back_edges =
loop_header->GetLoopInformation()->GetBackEdges().Size();
- if (num_back_edges != 1) {
- std::stringstream error;
- error << "Loop defined by header " << id << " has "
- << num_back_edges << " back edge(s).";
- errors_.push_back(error.str());
+ if (num_back_edges == 0) {
+ AddError(StringPrintf(
+ "Loop defined by header %d has no back edge.",
+ id));
+ } else if (num_back_edges > 1) {
+ AddError(StringPrintf(
+ "Loop defined by header %d has several back edges: %zu.",
+ id,
+ num_back_edges));
}
// Ensure all blocks in the loop are dominated by the loop header.
@@ -261,10 +243,9 @@
for (uint32_t i : loop_blocks.Indexes()) {
HBasicBlock* loop_block = GetGraph()->GetBlocks().Get(i);
if (!loop_header->Dominates(loop_block)) {
- std::stringstream error;
- error << "Loop block " << loop_block->GetBlockId()
- << " not dominated by loop header " << id;
- errors_.push_back(error.str());
+ AddError(StringPrintf("Loop block %d not dominated by loop header %d.",
+ loop_block->GetBlockId(),
+ id));
}
}
}
@@ -277,12 +258,10 @@
!use_it.Done(); use_it.Advance()) {
HInstruction* use = use_it.Current()->GetUser();
if (!use->IsPhi() && !instruction->StrictlyDominates(use)) {
- std::stringstream error;
- error << "Instruction " << instruction->GetId()
- << " in block " << current_block_->GetBlockId()
- << " does not dominate use " << use->GetId()
- << " in block " << use->GetBlock()->GetBlockId() << ".";
- errors_.push_back(error.str());
+ AddError(StringPrintf("Instruction %d in block %d does not dominate "
+ "use %d in block %d.",
+ instruction->GetId(), current_block_->GetBlockId(),
+ use->GetId(), use->GetBlock()->GetBlockId()));
}
}
@@ -294,13 +273,12 @@
HInstruction* env_instruction = environment->GetInstructionAt(i);
if (env_instruction != nullptr
&& !env_instruction->StrictlyDominates(instruction)) {
- std::stringstream error;
- error << "Instruction " << env_instruction->GetId()
- << " in environment of instruction " << instruction->GetId()
- << " from block " << current_block_->GetBlockId()
- << " does not dominate instruction " << instruction->GetId()
- << ".";
- errors_.push_back(error.str());
+ AddError(StringPrintf("Instruction %d in environment of instruction %d "
+ "from block %d does not dominate instruction %d.",
+ env_instruction->GetId(),
+ instruction->GetId(),
+ current_block_->GetBlockId(),
+ instruction->GetId()));
}
}
}
@@ -311,25 +289,21 @@
// Ensure the first input of a phi is not itself.
if (phi->InputAt(0) == phi) {
- std::stringstream error;
- error << "Loop phi " << phi->GetId()
- << " in block " << phi->GetBlock()->GetBlockId()
- << " is its own first input.";
- errors_.push_back(error.str());
+ AddError(StringPrintf("Loop phi %d in block %d is its own first input.",
+ phi->GetId(),
+ phi->GetBlock()->GetBlockId()));
}
- // Ensure the number of phi inputs is the same as the number of
+ // Ensure the number of inputs of a phi is the same as the number of
// its predecessors.
const GrowableArray<HBasicBlock*>& predecessors =
phi->GetBlock()->GetPredecessors();
if (phi->InputCount() != predecessors.Size()) {
- std::stringstream error;
- error << "Phi " << phi->GetId()
- << " in block " << phi->GetBlock()->GetBlockId()
- << " has " << phi->InputCount() << " inputs, but block "
- << phi->GetBlock()->GetBlockId() << " has "
- << predecessors.Size() << " predecessors.";
- errors_.push_back(error.str());
+ AddError(StringPrintf(
+ "Phi %d in block %d has %zu inputs, "
+ "but block %d has %zu predecessors.",
+ phi->GetId(), phi->GetBlock()->GetBlockId(), phi->InputCount(),
+ phi->GetBlock()->GetBlockId(), predecessors.Size()));
} else {
// Ensure phi input at index I either comes from the Ith
// predecessor or from a block that dominates this predecessor.
@@ -338,13 +312,11 @@
HBasicBlock* predecessor = predecessors.Get(i);
if (!(input->GetBlock() == predecessor
|| input->GetBlock()->Dominates(predecessor))) {
- std::stringstream error;
- error << "Input " << input->GetId() << " at index " << i
- << " of phi " << phi->GetId()
- << " from block " << phi->GetBlock()->GetBlockId()
- << " is not defined in predecessor number " << i
- << " nor in a block dominating it.";
- errors_.push_back(error.str());
+ AddError(StringPrintf(
+ "Input %d at index %zu of phi %d from block %d is not defined in "
+ "predecessor number %zu nor in a block dominating it.",
+ input->GetId(), i, phi->GetId(), phi->GetBlock()->GetBlockId(),
+ i));
}
}
}
@@ -369,69 +341,61 @@
if (input->IsIntConstant()) {
int value = input->AsIntConstant()->GetValue();
if (value != 0 && value != 1) {
- std::stringstream error;
- error << "If instruction " << instruction->GetId()
- << " has a non-boolean constant input whose value is: "
- << value << ".";
- errors_.push_back(error.str());
+ AddError(StringPrintf(
+ "If instruction %d has a non-Boolean constant input "
+ "whose value is: %d.",
+ instruction->GetId(),
+ value));
}
} else if (instruction->InputAt(0)->GetType() != Primitive::kPrimBoolean) {
- std::stringstream error;
- error << "If instruction " << instruction->GetId()
- << " has a non-boolean input type: "
- << instruction->InputAt(0)->GetType() << ".";
- errors_.push_back(error.str());
+ AddError(StringPrintf(
+ "If instruction %d has a non-Boolean input type: %s.",
+ instruction->GetId(),
+ Primitive::PrettyDescriptor(instruction->InputAt(0)->GetType())));
}
}
void SSAChecker::VisitCondition(HCondition* op) {
VisitInstruction(op);
if (op->GetType() != Primitive::kPrimBoolean) {
- std::stringstream error;
- error << "Condition " << op->DebugName() << " " << op->GetId()
- << " has a non-boolean result type: "
- << op->GetType() << ".";
- errors_.push_back(error.str());
+ AddError(StringPrintf(
+ "Condition %s %d has a non-Boolean result type: %s.",
+ op->DebugName(), op->GetId(),
+ Primitive::PrettyDescriptor(op->GetType())));
}
HInstruction* lhs = op->InputAt(0);
HInstruction* rhs = op->InputAt(1);
if (lhs->GetType() == Primitive::kPrimNot) {
if (!op->IsEqual() && !op->IsNotEqual()) {
- std::stringstream error;
- error << "Condition " << op->DebugName() << " " << op->GetId()
- << " uses an object as left-hand side input.";
- errors_.push_back(error.str());
+ AddError(StringPrintf(
+ "Condition %s %d uses an object as left-hand side input.",
+ op->DebugName(), op->GetId()));
}
if (rhs->IsIntConstant() && rhs->AsIntConstant()->GetValue() != 0) {
- std::stringstream error;
- error << "Condition " << op->DebugName() << " " << op->GetId()
- << " compares an object with a non-0 integer: "
- << rhs->AsIntConstant()->GetValue()
- << ".";
- errors_.push_back(error.str());
+ AddError(StringPrintf(
+ "Condition %s %d compares an object with a non-zero integer: %d.",
+ op->DebugName(), op->GetId(),
+ rhs->AsIntConstant()->GetValue()));
}
} else if (rhs->GetType() == Primitive::kPrimNot) {
if (!op->IsEqual() && !op->IsNotEqual()) {
- std::stringstream error;
- error << "Condition " << op->DebugName() << " " << op->GetId()
- << " uses an object as right-hand side input.";
- errors_.push_back(error.str());
+ AddError(StringPrintf(
+ "Condition %s %d uses an object as right-hand side input.",
+ op->DebugName(), op->GetId()));
}
if (lhs->IsIntConstant() && lhs->AsIntConstant()->GetValue() != 0) {
- std::stringstream error;
- error << "Condition " << op->DebugName() << " " << op->GetId()
- << " compares a non-0 integer with an object: "
- << lhs->AsIntConstant()->GetValue()
- << ".";
- errors_.push_back(error.str());
+ AddError(StringPrintf(
+ "Condition %s %d compares a non-zero integer with an object: %d.",
+ op->DebugName(), op->GetId(),
+ lhs->AsIntConstant()->GetValue()));
}
} else if (PrimitiveKind(lhs->GetType()) != PrimitiveKind(rhs->GetType())) {
- std::stringstream error;
- error << "Condition " << op->DebugName() << " " << op->GetId()
- << " has inputs of different type: "
- << lhs->GetType() << ", and " << rhs->GetType()
- << ".";
- errors_.push_back(error.str());
+ AddError(StringPrintf(
+ "Condition %s %d has inputs of different types: "
+ "%s, and %s.",
+ op->DebugName(), op->GetId(),
+ Primitive::PrettyDescriptor(lhs->GetType()),
+ Primitive::PrettyDescriptor(rhs->GetType())));
}
}
@@ -439,41 +403,40 @@
VisitInstruction(op);
if (op->IsUShr() || op->IsShr() || op->IsShl()) {
if (PrimitiveKind(op->InputAt(1)->GetType()) != Primitive::kPrimInt) {
- std::stringstream error;
- error << "Shift operation " << op->DebugName() << " " << op->GetId()
- << " has a non-int kind second input: "
- << op->InputAt(1)->DebugName() << " of type " << op->InputAt(1)->GetType()
- << ".";
- errors_.push_back(error.str());
+ AddError(StringPrintf(
+ "Shift operation %s %d has a non-int kind second input: "
+ "%s of type %s.",
+ op->DebugName(), op->GetId(),
+ op->InputAt(1)->DebugName(),
+ Primitive::PrettyDescriptor(op->InputAt(1)->GetType())));
}
} else {
if (PrimitiveKind(op->InputAt(1)->GetType()) != PrimitiveKind(op->InputAt(0)->GetType())) {
- std::stringstream error;
- error << "Binary operation " << op->DebugName() << " " << op->GetId()
- << " has inputs of different type: "
- << op->InputAt(0)->GetType() << ", and " << op->InputAt(1)->GetType()
- << ".";
- errors_.push_back(error.str());
+ AddError(StringPrintf(
+ "Binary operation %s %d has inputs of different types: "
+ "%s, and %s.",
+ op->DebugName(), op->GetId(),
+ Primitive::PrettyDescriptor(op->InputAt(0)->GetType()),
+ Primitive::PrettyDescriptor(op->InputAt(1)->GetType())));
}
}
if (op->IsCompare()) {
if (op->GetType() != Primitive::kPrimInt) {
- std::stringstream error;
- error << "Compare operation " << op->GetId()
- << " has a non-int result type: "
- << op->GetType() << ".";
- errors_.push_back(error.str());
+ AddError(StringPrintf(
+ "Compare operation %d has a non-int result type: %s.",
+ op->GetId(),
+ Primitive::PrettyDescriptor(op->GetType())));
}
} else {
// Use the first input, so that we can also make this check for shift operations.
if (PrimitiveKind(op->GetType()) != PrimitiveKind(op->InputAt(0)->GetType())) {
- std::stringstream error;
- error << "Binary operation " << op->DebugName() << " " << op->GetId()
- << " has a result type different than its input type: "
- << op->GetType() << ", and " << op->InputAt(1)->GetType()
- << ".";
- errors_.push_back(error.str());
+ AddError(StringPrintf(
+ "Binary operation %s %d has a result type different "
+ "from its input type: %s vs %s.",
+ op->DebugName(), op->GetId(),
+ Primitive::PrettyDescriptor(op->GetType()),
+ Primitive::PrettyDescriptor(op->InputAt(1)->GetType())));
}
}
}
diff --git a/compiler/optimizing/graph_checker.h b/compiler/optimizing/graph_checker.h
index ae1557b..5ec3003 100644
--- a/compiler/optimizing/graph_checker.h
+++ b/compiler/optimizing/graph_checker.h
@@ -60,6 +60,11 @@
}
protected:
+ // Report a new error.
+ void AddError(const std::string& error) {
+ errors_.push_back(error);
+ }
+
ArenaAllocator* const allocator_;
// The block currently visited.
HBasicBlock* current_block_ = nullptr;
diff --git a/patchoat/patchoat.cc b/patchoat/patchoat.cc
index 6c86c7b..2059a96 100644
--- a/patchoat/patchoat.cc
+++ b/patchoat/patchoat.cc
@@ -48,30 +48,6 @@
namespace art {
-static InstructionSet ElfISAToInstructionSet(Elf32_Word isa, Elf32_Word e_flags) {
- switch (isa) {
- case EM_ARM:
- return kArm;
- case EM_AARCH64:
- return kArm64;
- case EM_386:
- return kX86;
- case EM_X86_64:
- return kX86_64;
- case EM_MIPS:
- if (((e_flags & EF_MIPS_ARCH) == EF_MIPS_ARCH_32R2) ||
- ((e_flags & EF_MIPS_ARCH) == EF_MIPS_ARCH_32R6)) {
- return kMips;
- } else if ((e_flags & EF_MIPS_ARCH) == EF_MIPS_ARCH_64R6) {
- return kMips64;
- } else {
- return kNone;
- }
- default:
- return kNone;
- }
-}
-
static bool LocationToFilename(const std::string& location, InstructionSet isa,
std::string* filename) {
bool has_system = false;
@@ -219,7 +195,7 @@
LOG(ERROR) << "unable to read elf header";
return false;
}
- isa = ElfISAToInstructionSet(elf_hdr.e_machine, elf_hdr.e_flags);
+ isa = GetInstructionSetFromELF(elf_hdr.e_machine, elf_hdr.e_flags);
}
const char* isa_name = GetInstructionSetString(isa);
std::string image_filename;
diff --git a/runtime/arch/instruction_set.cc b/runtime/arch/instruction_set.cc
index 5ab461b..81ca010 100644
--- a/runtime/arch/instruction_set.cc
+++ b/runtime/arch/instruction_set.cc
@@ -16,6 +16,8 @@
#include "instruction_set.h"
+// Explicitly include our own elf.h to avoid Linux and other dependencies.
+#include "../elf.h"
#include "globals.h"
namespace art {
@@ -63,6 +65,29 @@
return kNone;
}
+InstructionSet GetInstructionSetFromELF(uint16_t e_machine, uint32_t e_flags) {
+ switch (e_machine) {
+ case EM_ARM:
+ return kArm;
+ case EM_AARCH64:
+ return kArm64;
+ case EM_386:
+ return kX86;
+ case EM_X86_64:
+ return kX86_64;
+ case EM_MIPS: {
+ if ((e_flags & EF_MIPS_ARCH) == EF_MIPS_ARCH_32R2 ||
+ (e_flags & EF_MIPS_ARCH) == EF_MIPS_ARCH_32R6) {
+ return kMips;
+ } else if ((e_flags & EF_MIPS_ARCH) == EF_MIPS_ARCH_64R6) {
+ return kMips64;
+ }
+ break;
+ }
+ }
+ return kNone;
+}
+
size_t GetInstructionSetAlignment(InstructionSet isa) {
switch (isa) {
case kArm:
diff --git a/runtime/arch/instruction_set.h b/runtime/arch/instruction_set.h
index 9135e58..9cfd2eb 100644
--- a/runtime/arch/instruction_set.h
+++ b/runtime/arch/instruction_set.h
@@ -80,6 +80,8 @@
// Note: Returns kNone when the string cannot be parsed to a known value.
InstructionSet GetInstructionSetFromString(const char* instruction_set);
+InstructionSet GetInstructionSetFromELF(uint16_t e_machine, uint32_t e_flags);
+
static inline size_t GetInstructionSetPointerSize(InstructionSet isa) {
switch (isa) {
case kArm:
diff --git a/runtime/elf_file.cc b/runtime/elf_file.cc
index 1b91aa6..a22e274 100644
--- a/runtime/elf_file.cc
+++ b/runtime/elf_file.cc
@@ -1313,35 +1313,7 @@
CHECK(program_header_only_) << file_->GetPath();
if (executable) {
- InstructionSet elf_ISA = kNone;
- switch (GetHeader().e_machine) {
- case EM_ARM: {
- elf_ISA = kArm;
- break;
- }
- case EM_AARCH64: {
- elf_ISA = kArm64;
- break;
- }
- case EM_386: {
- elf_ISA = kX86;
- break;
- }
- case EM_X86_64: {
- elf_ISA = kX86_64;
- break;
- }
- case EM_MIPS: {
- if ((GetHeader().e_flags & EF_MIPS_ARCH) == EF_MIPS_ARCH_32R2 ||
- (GetHeader().e_flags & EF_MIPS_ARCH) == EF_MIPS_ARCH_32R6) {
- elf_ISA = kMips;
- } else if ((GetHeader().e_flags & EF_MIPS_ARCH) == EF_MIPS_ARCH_64R6) {
- elf_ISA = kMips64;
- }
- break;
- }
- }
-
+ InstructionSet elf_ISA = GetInstructionSetFromELF(GetHeader().e_machine, GetHeader().e_flags);
if (elf_ISA != kRuntimeISA) {
std::ostringstream oss;
oss << "Expected ISA " << kRuntimeISA << " but found " << elf_ISA;
diff --git a/runtime/gc/accounting/card_table-inl.h b/runtime/gc/accounting/card_table-inl.h
index 15562e5..83ad33e 100644
--- a/runtime/gc/accounting/card_table-inl.h
+++ b/runtime/gc/accounting/card_table-inl.h
@@ -48,7 +48,7 @@
#endif
}
-template <typename Visitor>
+template <bool kClearCard, typename Visitor>
inline size_t CardTable::Scan(ContinuousSpaceBitmap* bitmap, uint8_t* scan_begin, uint8_t* scan_end,
const Visitor& visitor, const uint8_t minimum_age) const {
DCHECK_GE(scan_begin, reinterpret_cast<uint8_t*>(bitmap->HeapBegin()));
@@ -66,6 +66,9 @@
uintptr_t start = reinterpret_cast<uintptr_t>(AddrFromCard(card_cur));
bitmap->VisitMarkedRange(start, start + kCardSize, visitor);
++cards_scanned;
+ if (kClearCard) {
+ *card_cur = 0;
+ }
}
++card_cur;
}
@@ -95,6 +98,9 @@
<< "card " << static_cast<size_t>(*card) << " intptr_t " << (start_word & 0xFF);
bitmap->VisitMarkedRange(start, start + kCardSize, visitor);
++cards_scanned;
+ if (kClearCard) {
+ *card = 0;
+ }
}
start_word >>= 8;
start += kCardSize;
@@ -109,6 +115,9 @@
uintptr_t start = reinterpret_cast<uintptr_t>(AddrFromCard(card_cur));
bitmap->VisitMarkedRange(start, start + kCardSize, visitor);
++cards_scanned;
+ if (kClearCard) {
+ *card_cur = 0;
+ }
}
++card_cur;
}
diff --git a/runtime/gc/accounting/card_table.h b/runtime/gc/accounting/card_table.h
index 9bd3fba..a84cf34 100644
--- a/runtime/gc/accounting/card_table.h
+++ b/runtime/gc/accounting/card_table.h
@@ -101,7 +101,7 @@
// For every dirty at least minumum age between begin and end invoke the visitor with the
// specified argument. Returns how many cards the visitor was run on.
- template <typename Visitor>
+ template <bool kClearCard, typename Visitor>
size_t Scan(SpaceBitmap<kObjectAlignment>* bitmap, uint8_t* scan_begin, uint8_t* scan_end,
const Visitor& visitor,
const uint8_t minimum_age = kCardDirty) const
diff --git a/runtime/gc/collector/mark_sweep.cc b/runtime/gc/collector/mark_sweep.cc
index 80f7968..04fb694 100644
--- a/runtime/gc/collector/mark_sweep.cc
+++ b/runtime/gc/collector/mark_sweep.cc
@@ -687,12 +687,12 @@
CardScanTask(ThreadPool* thread_pool, MarkSweep* mark_sweep,
accounting::ContinuousSpaceBitmap* bitmap,
uint8_t* begin, uint8_t* end, uint8_t minimum_age, size_t mark_stack_size,
- Object** mark_stack_obj)
+ Object** mark_stack_obj, bool clear_card)
: MarkStackTask<false>(thread_pool, mark_sweep, mark_stack_size, mark_stack_obj),
bitmap_(bitmap),
begin_(begin),
end_(end),
- minimum_age_(minimum_age) {
+ minimum_age_(minimum_age), clear_card_(clear_card) {
}
protected:
@@ -700,6 +700,7 @@
uint8_t* const begin_;
uint8_t* const end_;
const uint8_t minimum_age_;
+ const bool clear_card_;
virtual void Finalize() {
delete this;
@@ -708,7 +709,9 @@
virtual void Run(Thread* self) NO_THREAD_SAFETY_ANALYSIS {
ScanObjectParallelVisitor visitor(this);
accounting::CardTable* card_table = mark_sweep_->GetHeap()->GetCardTable();
- size_t cards_scanned = card_table->Scan(bitmap_, begin_, end_, visitor, minimum_age_);
+ size_t cards_scanned = clear_card_ ?
+ card_table->Scan<true>(bitmap_, begin_, end_, visitor, minimum_age_) :
+ card_table->Scan<false>(bitmap_, begin_, end_, visitor, minimum_age_);
VLOG(heap) << "Parallel scanning cards " << reinterpret_cast<void*>(begin_) << " - "
<< reinterpret_cast<void*>(end_) << " = " << cards_scanned;
// Finish by emptying our local mark stack.
@@ -763,6 +766,11 @@
// Calculate how much address range each task gets.
const size_t card_delta = RoundUp(address_range / thread_count + 1,
accounting::CardTable::kCardSize);
+ // If paused and the space is neither zygote nor image space, we could clear the dirty
+ // cards to avoid accumulating them to increase card scanning load in the following GC
+ // cycles. We need to keep dirty cards of image space and zygote space in order to track
+ // references to the other spaces.
+ bool clear_card = paused && !space->IsZygoteSpace() && !space->IsImageSpace();
// Create the worker tasks for this space.
while (card_begin != card_end) {
// Add a range of cards.
@@ -777,7 +785,7 @@
// Add the new task to the thread pool.
auto* task = new CardScanTask(thread_pool, this, space->GetMarkBitmap(), card_begin,
card_begin + card_increment, minimum_age,
- mark_stack_increment, mark_stack_end);
+ mark_stack_increment, mark_stack_end, clear_card);
thread_pool->AddTask(self, task);
card_begin += card_increment;
}
@@ -811,8 +819,14 @@
}
TimingLogger::ScopedTiming t(name, GetTimings());
ScanObjectVisitor visitor(this);
- card_table->Scan(space->GetMarkBitmap(), space->Begin(), space->End(), visitor,
- minimum_age);
+ bool clear_card = paused && !space->IsZygoteSpace() && !space->IsImageSpace();
+ if (clear_card) {
+ card_table->Scan<true>(space->GetMarkBitmap(), space->Begin(), space->End(), visitor,
+ minimum_age);
+ } else {
+ card_table->Scan<false>(space->GetMarkBitmap(), space->Begin(), space->End(), visitor,
+ minimum_age);
+ }
}
}
}
diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc
index eed9352..6ba30c6 100644
--- a/runtime/gc/heap.cc
+++ b/runtime/gc/heap.cc
@@ -2385,8 +2385,8 @@
// Attempt to see if the card table missed the reference.
ScanVisitor scan_visitor;
uint8_t* byte_cover_begin = reinterpret_cast<uint8_t*>(card_table->AddrFromCard(card_addr));
- card_table->Scan(bitmap, byte_cover_begin,
- byte_cover_begin + accounting::CardTable::kCardSize, scan_visitor);
+ card_table->Scan<false>(bitmap, byte_cover_begin,
+ byte_cover_begin + accounting::CardTable::kCardSize, scan_visitor);
}
// Search to see if any of the roots reference our object.
diff --git a/runtime/monitor.cc b/runtime/monitor.cc
index ef63080..5e33380 100644
--- a/runtime/monitor.cc
+++ b/runtime/monitor.cc
@@ -933,8 +933,11 @@
PrettyTypeOf(pretty_object).c_str());
} else {
// - waiting on <0x6008c468> (a java.lang.Class<java.lang.ref.ReferenceQueue>)
+ // Call PrettyTypeOf before IdentityHashCode since IdentityHashCode can cause thread
+ // suspension and move pretty_object.
+ const std::string pretty_type(PrettyTypeOf(pretty_object));
os << wait_message << StringPrintf("<0x%08x> (a %s)", pretty_object->IdentityHashCode(),
- PrettyTypeOf(pretty_object).c_str());
+ pretty_type.c_str());
}
}
// - waiting to lock <0x613f83d8> (a java.lang.Object) held by thread 5
diff --git a/runtime/primitive.cc b/runtime/primitive.cc
index a639f93..d29a060 100644
--- a/runtime/primitive.cc
+++ b/runtime/primitive.cc
@@ -31,6 +31,11 @@
"PrimVoid",
};
+const char* Primitive::PrettyDescriptor(Primitive::Type type) {
+ CHECK(Primitive::kPrimNot <= type && type <= Primitive::kPrimVoid) << static_cast<int>(type);
+ return kTypeNames[type];
+}
+
std::ostream& operator<<(std::ostream& os, const Primitive::Type& type) {
int32_t int_type = static_cast<int32_t>(type);
if (type >= Primitive::kPrimNot && type <= Primitive::kPrimVoid) {
diff --git a/runtime/primitive.h b/runtime/primitive.h
index afcc64d..50d171c 100644
--- a/runtime/primitive.h
+++ b/runtime/primitive.h
@@ -146,6 +146,8 @@
}
}
+ static const char* PrettyDescriptor(Type type);
+
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(Primitive);
};
diff --git a/test/082-inline-execute/src/Main.java b/test/082-inline-execute/src/Main.java
index 862fe06..a737ccd 100644
--- a/test/082-inline-execute/src/Main.java
+++ b/test/082-inline-execute/src/Main.java
@@ -34,6 +34,7 @@
test_Math_max_F();
test_Math_min_D();
test_Math_max_D();
+ test_Math_sqrt();
test_Math_ceil();
test_Math_floor();
test_Math_rint();
@@ -54,6 +55,7 @@
test_StrictMath_max_F();
test_StrictMath_min_D();
test_StrictMath_max_D();
+ test_StrictMath_sqrt();
test_StrictMath_ceil();
test_StrictMath_floor();
test_StrictMath_rint();
@@ -298,6 +300,7 @@
}
public static void test_Math_abs_I() {
+ Math.abs(-1);
Assert.assertEquals(Math.abs(0), 0);
Assert.assertEquals(Math.abs(123), 123);
Assert.assertEquals(Math.abs(-123), 123);
@@ -308,6 +311,7 @@
}
public static void test_Math_abs_J() {
+ Math.abs(-1L);
Assert.assertEquals(Math.abs(0L), 0L);
Assert.assertEquals(Math.abs(123L), 123L);
Assert.assertEquals(Math.abs(-123L), 123L);
@@ -317,6 +321,7 @@
}
public static void test_Math_min_I() {
+ Math.min(1, 0);
Assert.assertEquals(Math.min(0, 0), 0);
Assert.assertEquals(Math.min(1, 0), 0);
Assert.assertEquals(Math.min(0, 1), 0);
@@ -326,6 +331,7 @@
}
public static void test_Math_max_I() {
+ Math.max(1, 0);
Assert.assertEquals(Math.max(0, 0), 0);
Assert.assertEquals(Math.max(1, 0), 1);
Assert.assertEquals(Math.max(0, 1), 1);
@@ -335,6 +341,7 @@
}
public static void test_Math_min_J() {
+ Math.min(1L, 0L);
Assert.assertEquals(Math.min(0L, 0L), 0L);
Assert.assertEquals(Math.min(1L, 0L), 0L);
Assert.assertEquals(Math.min(0L, 1L), 0L);
@@ -344,6 +351,7 @@
}
public static void test_Math_max_J() {
+ Math.max(1L, 0L);
Assert.assertEquals(Math.max(0L, 0L), 0L);
Assert.assertEquals(Math.max(1L, 0L), 1L);
Assert.assertEquals(Math.max(0L, 1L), 1L);
@@ -353,6 +361,7 @@
}
public static void test_Math_min_F() {
+ Math.min(1.0f, Float.NaN);
Assert.assertTrue(Float.isNaN(Math.min(1.0f, Float.NaN)));
Assert.assertTrue(Float.isNaN(Math.min(Float.NaN, 1.0f)));
Assert.assertEquals(Math.min(-0.0f, 0.0f), -0.0f);
@@ -367,6 +376,7 @@
}
public static void test_Math_max_F() {
+ Math.max(1.0f, Float.NaN);
Assert.assertTrue(Float.isNaN(Math.max(1.0f, Float.NaN)));
Assert.assertTrue(Float.isNaN(Math.max(Float.NaN, 1.0f)));
Assert.assertEquals(Math.max(-0.0f, 0.0f), 0.0f);
@@ -381,6 +391,7 @@
}
public static void test_Math_min_D() {
+ Math.min(1.0d, Double.NaN);
Assert.assertTrue(Double.isNaN(Math.min(1.0d, Double.NaN)));
Assert.assertTrue(Double.isNaN(Math.min(Double.NaN, 1.0d)));
Assert.assertEquals(Math.min(-0.0d, 0.0d), -0.0d);
@@ -395,6 +406,7 @@
}
public static void test_Math_max_D() {
+ Math.max(1.0d, Double.NaN);
Assert.assertTrue(Double.isNaN(Math.max(1.0d, Double.NaN)));
Assert.assertTrue(Double.isNaN(Math.max(Double.NaN, 1.0d)));
Assert.assertEquals(Math.max(-0.0d, 0.0d), 0.0d);
@@ -408,7 +420,15 @@
Assert.assertEquals(Math.max(Double.MIN_VALUE, Double.MAX_VALUE), Double.MAX_VALUE);
}
+ public static void test_Math_sqrt() {
+ Math.sqrt(+4.0);
+ Assert.assertEquals(Math.sqrt(+4.0), +2.0d, 0.0);
+ Assert.assertEquals(Math.sqrt(+49.0), +7.0d, 0.0);
+ Assert.assertEquals(Math.sqrt(+1.44), +1.2d, 0.0);
+ }
+
public static void test_Math_ceil() {
+ Math.ceil(-0.9);
Assert.assertEquals(Math.ceil(+0.0), +0.0d, 0.0);
Assert.assertEquals(Math.ceil(-0.0), -0.0d, 0.0);
Assert.assertEquals(Math.ceil(-0.9), -0.0d, 0.0);
@@ -430,6 +450,7 @@
}
public static void test_Math_floor() {
+ Math.floor(+2.1);
Assert.assertEquals(Math.floor(+0.0), +0.0d, 0.0);
Assert.assertEquals(Math.floor(-0.0), -0.0d, 0.0);
Assert.assertEquals(Math.floor(+2.0), +2.0d, 0.0);
@@ -448,6 +469,7 @@
}
public static void test_Math_rint() {
+ Math.rint(+2.1);
Assert.assertEquals(Math.rint(+0.0), +0.0d, 0.0);
Assert.assertEquals(Math.rint(-0.0), -0.0d, 0.0);
Assert.assertEquals(Math.rint(+2.0), +2.0d, 0.0);
@@ -466,6 +488,7 @@
}
public static void test_Math_round_D() {
+ Math.round(2.1d);
Assert.assertEquals(Math.round(+0.0d), (long)+0.0);
Assert.assertEquals(Math.round(-0.0d), (long)+0.0);
Assert.assertEquals(Math.round(2.0d), 2l);
@@ -487,6 +510,7 @@
}
public static void test_Math_round_F() {
+ Math.round(2.1f);
Assert.assertEquals(Math.round(+0.0f), (int)+0.0);
Assert.assertEquals(Math.round(-0.0f), (int)+0.0);
Assert.assertEquals(Math.round(2.0f), 2);
@@ -507,6 +531,7 @@
}
public static void test_StrictMath_abs_I() {
+ StrictMath.abs(-1);
Assert.assertEquals(StrictMath.abs(0), 0);
Assert.assertEquals(StrictMath.abs(123), 123);
Assert.assertEquals(StrictMath.abs(-123), 123);
@@ -517,6 +542,7 @@
}
public static void test_StrictMath_abs_J() {
+ StrictMath.abs(-1L);
Assert.assertEquals(StrictMath.abs(0L), 0L);
Assert.assertEquals(StrictMath.abs(123L), 123L);
Assert.assertEquals(StrictMath.abs(-123L), 123L);
@@ -526,6 +552,7 @@
}
public static void test_StrictMath_min_I() {
+ StrictMath.min(1, 0);
Assert.assertEquals(StrictMath.min(0, 0), 0);
Assert.assertEquals(StrictMath.min(1, 0), 0);
Assert.assertEquals(StrictMath.min(0, 1), 0);
@@ -535,6 +562,7 @@
}
public static void test_StrictMath_max_I() {
+ StrictMath.max(1, 0);
Assert.assertEquals(StrictMath.max(0, 0), 0);
Assert.assertEquals(StrictMath.max(1, 0), 1);
Assert.assertEquals(StrictMath.max(0, 1), 1);
@@ -544,6 +572,7 @@
}
public static void test_StrictMath_min_J() {
+ StrictMath.min(1L, 0L);
Assert.assertEquals(StrictMath.min(0L, 0L), 0L);
Assert.assertEquals(StrictMath.min(1L, 0L), 0L);
Assert.assertEquals(StrictMath.min(0L, 1L), 0L);
@@ -553,6 +582,7 @@
}
public static void test_StrictMath_max_J() {
+ StrictMath.max(1L, 0L);
Assert.assertEquals(StrictMath.max(0L, 0L), 0L);
Assert.assertEquals(StrictMath.max(1L, 0L), 1L);
Assert.assertEquals(StrictMath.max(0L, 1L), 1L);
@@ -562,6 +592,7 @@
}
public static void test_StrictMath_min_F() {
+ StrictMath.min(1.0f, Float.NaN);
Assert.assertTrue(Float.isNaN(StrictMath.min(1.0f, Float.NaN)));
Assert.assertTrue(Float.isNaN(StrictMath.min(Float.NaN, 1.0f)));
Assert.assertEquals(StrictMath.min(-0.0f, 0.0f), -0.0f);
@@ -576,6 +607,7 @@
}
public static void test_StrictMath_max_F() {
+ StrictMath.max(1.0f, Float.NaN);
Assert.assertTrue(Float.isNaN(StrictMath.max(1.0f, Float.NaN)));
Assert.assertTrue(Float.isNaN(StrictMath.max(Float.NaN, 1.0f)));
Assert.assertEquals(StrictMath.max(-0.0f, 0.0f), 0.0f);
@@ -590,6 +622,7 @@
}
public static void test_StrictMath_min_D() {
+ StrictMath.min(1.0d, Double.NaN);
Assert.assertTrue(Double.isNaN(StrictMath.min(1.0d, Double.NaN)));
Assert.assertTrue(Double.isNaN(StrictMath.min(Double.NaN, 1.0d)));
Assert.assertEquals(StrictMath.min(-0.0d, 0.0d), -0.0d);
@@ -604,6 +637,7 @@
}
public static void test_StrictMath_max_D() {
+ StrictMath.max(1.0d, Double.NaN);
Assert.assertTrue(Double.isNaN(StrictMath.max(1.0d, Double.NaN)));
Assert.assertTrue(Double.isNaN(StrictMath.max(Double.NaN, 1.0d)));
Assert.assertEquals(StrictMath.max(-0.0d, 0.0d), 0.0d);
@@ -617,7 +651,15 @@
Assert.assertEquals(StrictMath.max(Double.MIN_VALUE, Double.MAX_VALUE), Double.MAX_VALUE);
}
+ public static void test_StrictMath_sqrt() {
+ StrictMath.sqrt(+4.0);
+ Assert.assertEquals(StrictMath.sqrt(+4.0), +2.0d, 0.0);
+ Assert.assertEquals(StrictMath.sqrt(+49.0), +7.0d, 0.0);
+ Assert.assertEquals(StrictMath.sqrt(+1.44), +1.2d, 0.0);
+ }
+
public static void test_StrictMath_ceil() {
+ StrictMath.ceil(-0.9);
Assert.assertEquals(StrictMath.ceil(+0.0), +0.0d, 0.0);
Assert.assertEquals(StrictMath.ceil(-0.0), -0.0d, 0.0);
Assert.assertEquals(StrictMath.ceil(-0.9), -0.0d, 0.0);
@@ -639,6 +681,7 @@
}
public static void test_StrictMath_floor() {
+ StrictMath.floor(+2.1);
Assert.assertEquals(StrictMath.floor(+0.0), +0.0d, 0.0);
Assert.assertEquals(StrictMath.floor(-0.0), -0.0d, 0.0);
Assert.assertEquals(StrictMath.floor(+2.0), +2.0d, 0.0);
@@ -657,6 +700,7 @@
}
public static void test_StrictMath_rint() {
+ StrictMath.rint(+2.1);
Assert.assertEquals(StrictMath.rint(+0.0), +0.0d, 0.0);
Assert.assertEquals(StrictMath.rint(-0.0), -0.0d, 0.0);
Assert.assertEquals(StrictMath.rint(+2.0), +2.0d, 0.0);
@@ -675,6 +719,7 @@
}
public static void test_StrictMath_round_D() {
+ StrictMath.round(2.1d);
Assert.assertEquals(StrictMath.round(+0.0d), (long)+0.0);
Assert.assertEquals(StrictMath.round(-0.0d), (long)+0.0);
Assert.assertEquals(StrictMath.round(2.0d), 2l);
@@ -696,6 +741,7 @@
}
public static void test_StrictMath_round_F() {
+ StrictMath.round(2.1f);
Assert.assertEquals(StrictMath.round(+0.0f), (int)+0.0);
Assert.assertEquals(StrictMath.round(-0.0f), (int)+0.0);
Assert.assertEquals(StrictMath.round(2.0f), 2);
@@ -716,6 +762,7 @@
}
public static void test_Float_floatToRawIntBits() {
+ Float.floatToRawIntBits(-1.0f);
Assert.assertEquals(Float.floatToRawIntBits(-1.0f), 0xbf800000);
Assert.assertEquals(Float.floatToRawIntBits(0.0f), 0);
Assert.assertEquals(Float.floatToRawIntBits(1.0f), 0x3f800000);
@@ -725,6 +772,7 @@
}
public static void test_Float_intBitsToFloat() {
+ Float.intBitsToFloat(0xbf800000);
Assert.assertEquals(Float.intBitsToFloat(0xbf800000), -1.0f);
Assert.assertEquals(Float.intBitsToFloat(0x00000000), 0.0f);
Assert.assertEquals(Float.intBitsToFloat(0x3f800000), 1.0f);
@@ -734,6 +782,7 @@
}
public static void test_Double_doubleToRawLongBits() {
+ Double.doubleToRawLongBits(-1.0);
Assert.assertEquals(Double.doubleToRawLongBits(-1.0), 0xbff0000000000000L);
Assert.assertEquals(Double.doubleToRawLongBits(0.0), 0x0000000000000000L);
Assert.assertEquals(Double.doubleToRawLongBits(1.0), 0x3ff0000000000000L);
@@ -743,6 +792,7 @@
}
public static void test_Double_longBitsToDouble() {
+ Double.longBitsToDouble(0xbff0000000000000L);
Assert.assertEquals(Double.longBitsToDouble(0xbff0000000000000L), -1.0);
Assert.assertEquals(Double.longBitsToDouble(0x0000000000000000L), 0.0);
Assert.assertEquals(Double.longBitsToDouble(0x3ff0000000000000L), 1.0);
@@ -752,6 +802,7 @@
}
public static void test_Short_reverseBytes() {
+ Short.reverseBytes((short)0x1357);
Assert.assertEquals(Short.reverseBytes((short)0x0000), (short)0x0000);
Assert.assertEquals(Short.reverseBytes((short)0xffff), (short)0xffff);
Assert.assertEquals(Short.reverseBytes((short)0x8000), (short)0x0080);
@@ -763,6 +814,7 @@
}
public static void test_Integer_reverseBytes() {
+ Integer.reverseBytes(0x13579bdf);
Assert.assertEquals(Integer.reverseBytes(0x00000000), 0x00000000);
Assert.assertEquals(Integer.reverseBytes(0xffffffff), 0xffffffff);
Assert.assertEquals(Integer.reverseBytes(0x80000000), 0x00000080);
@@ -772,6 +824,7 @@
}
public static void test_Long_reverseBytes() {
+ Long.reverseBytes(0x13579bdf2468ace0L);
Assert.assertEquals(Long.reverseBytes(0x0000000000000000L), 0x0000000000000000L);
Assert.assertEquals(Long.reverseBytes(0xffffffffffffffffL), 0xffffffffffffffffL);
Assert.assertEquals(Long.reverseBytes(0x8000000000000000L), 0x0000000000000080L);
@@ -780,6 +833,7 @@
}
public static void test_Integer_reverse() {
+ Integer.reverse(0x12345678);
Assert.assertEquals(Integer.reverse(1), 0x80000000);
Assert.assertEquals(Integer.reverse(-1), 0xffffffff);
Assert.assertEquals(Integer.reverse(0), 0);
@@ -790,6 +844,7 @@
}
public static void test_Long_reverse() {
+ Long.reverse(0x1234567812345678L);
Assert.assertEquals(Long.reverse(1L), 0x8000000000000000L);
Assert.assertEquals(Long.reverse(-1L), 0xffffffffffffffffL);
Assert.assertEquals(Long.reverse(0L), 0L);
@@ -844,6 +899,7 @@
b[1] = 0x12;
b[2] = 0x11;
long address = (long)address_of.invoke(runtime, b);
+ peek_short.invoke(null, address, false);
Assert.assertEquals((short)peek_short.invoke(null, address, false), 0x1213); // Aligned read
Assert.assertEquals((short)peek_short.invoke(null, address + 1, false), 0x1112); // Unaligned read
}
@@ -856,6 +912,7 @@
b[3] = 0x12;
b[4] = 0x11;
long address = (long)address_of.invoke(runtime, b);
+ peek_int.invoke(null, address, false);
Assert.assertEquals((int)peek_int.invoke(null, address, false), 0x12131415);
Assert.assertEquals((int)peek_int.invoke(null, address + 1, false), 0x11121314);
}
@@ -872,6 +929,7 @@
b[7] = 0x12;
b[8] = 0x11;
long address = (long)address_of.invoke(runtime, b);
+ peek_long.invoke(null, address, false);
Assert.assertEquals((long)peek_long.invoke(null, address, false), 0x1213141516171819L);
Assert.assertEquals((long)peek_long.invoke(null, address + 1, false), 0x1112131415161718L);
}
diff --git a/test/114-ParallelGC/src/Main.java b/test/114-ParallelGC/src/Main.java
index 48f9bd3..df2243c 100644
--- a/test/114-ParallelGC/src/Main.java
+++ b/test/114-ParallelGC/src/Main.java
@@ -16,54 +16,36 @@
import java.util.ArrayList;
import java.util.List;
-import java.util.concurrent.BrokenBarrierException;
+import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.CyclicBarrier;
-import java.util.concurrent.SynchronousQueue;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
public class Main implements Runnable {
// Timeout in minutes. Make it larger than the run-test timeout to get a native thread dump by
// ART on timeout when running on the host.
- public final static long TIMEOUT_VALUE = 12;
+ private final static long TIMEOUT_VALUE = 7;
- public final static long MAX_SIZE = 1000; // Maximum size of array-list to allocate.
+ private final static long MAX_SIZE = 1000; // Maximum size of array-list to allocate.
+
+ private final static int THREAD_COUNT = 16;
+
+ // Use a couple of different forms of synchronizing to test some of these...
+ private final static AtomicInteger counter = new AtomicInteger();
+ private final static Object gate = new Object();
+ private volatile static int waitCount = 0;
public static void main(String[] args) throws Exception {
- Thread[] threads = new Thread[16];
+ Thread[] threads = new Thread[THREAD_COUNT];
- // Use a cyclic system of synchronous queues to pass a boolean token around.
- //
- // The combinations are:
- //
- // Worker receives: true false false true
- // Worker has OOM: false false true true
- // |
- // v
- // Value to pass: true false false false
- // Exit out of loop: false true true true
- // Wait on in queue: true false false true
- //
- // Finally, the workers are supposed to wait on the barrier to synchronize the GC run.
-
- CyclicBarrier barrier = new CyclicBarrier(threads.length);
- List<SynchronousQueue<Boolean>> queues = new ArrayList<SynchronousQueue<Boolean>>(
- threads.length);
- for (int i = 0; i < threads.length; i++) {
- queues.add(new SynchronousQueue<Boolean>());
- }
+ // This barrier is used to synchronize the threads starting to allocate.
+ // Note: Even though a barrier is not allocation-free, this one is fine, as it will be used
+ // before filling the heap.
+ CyclicBarrier startBarrier = new CyclicBarrier(threads.length);
for (int i = 0; i < threads.length; i++) {
- threads[i] = new Thread(new Main(i, queues.get(i), queues.get((i + 1) % threads.length),
- barrier));
+ threads[i] = new Thread(new Main(startBarrier));
+ threads[i].start();
}
- for (Thread thread : threads) {
- thread.start();
- }
-
- // Push off the cycle.
- checkTimeout(queues.get(0).offer(Boolean.TRUE, TIMEOUT_VALUE, TimeUnit.MINUTES));
// Wait for the threads to finish.
for (Thread thread : threads) {
@@ -72,85 +54,84 @@
// Allocate objects to definitely run GC before quitting.
try {
- for (int i = 0; i < 1000; i++) {
- new ArrayList<Object>(i);
+ ArrayList<Object> l = new ArrayList<Object>();
+ for (int i = 0; i < 100000; i++) {
+ l.add(new ArrayList<Object>(i));
}
} catch (OutOfMemoryError oom) {
}
+ new ArrayList<Object>(50);
}
- private static void checkTimeout(Object o) {
- checkTimeout(o != null);
+ private Main(CyclicBarrier startBarrier) {
+ this.startBarrier = startBarrier;
}
- private static void checkTimeout(boolean b) {
- if (!b) {
- // Something went wrong.
- System.out.println("Bad things happened, timeout.");
- System.exit(1);
- }
- }
-
- private final int id;
- private final SynchronousQueue<Boolean> waitOn;
- private final SynchronousQueue<Boolean> pushTo;
- private final CyclicBarrier finalBarrier;
-
- private Main(int id, SynchronousQueue<Boolean> waitOn, SynchronousQueue<Boolean> pushTo,
- CyclicBarrier finalBarrier) {
- this.id = id;
- this.waitOn = waitOn;
- this.pushTo = pushTo;
- this.finalBarrier = finalBarrier;
- }
+ private ArrayList<Object> store;
+ private CyclicBarrier startBarrier;
public void run() {
try {
work();
- } catch (Exception exc) {
- // Any exception is bad.
- exc.printStackTrace(System.err);
+ } catch (Throwable t) {
+ // Any exception or error getting here is bad.
+ try {
+ // May need allocations...
+ t.printStackTrace(System.err);
+ } catch (Throwable tInner) {
+ }
System.exit(1);
}
}
- public void work() throws BrokenBarrierException, InterruptedException, TimeoutException {
+ private void work() throws Exception {
+ // Any exceptions except an OOME in the allocation loop are bad and handed off to the
+ // caller which should abort the whole runtime.
+
ArrayList<Object> l = new ArrayList<Object>();
+ store = l; // Keep it alive.
- // Main loop.
- for (int i = 0; ; i++) {
- Boolean receivedB = waitOn.poll(TIMEOUT_VALUE, TimeUnit.MINUTES);
- checkTimeout(receivedB);
- boolean received = receivedB;
+ // Wait for the start signal.
+ startBarrier.await(TIMEOUT_VALUE, java.util.concurrent.TimeUnit.MINUTES);
- // This is the first stage, try to allocate up till MAX_SIZE.
- boolean oom = i >= MAX_SIZE;
- try {
- l.add(new ArrayList<Object>(i));
- } catch (OutOfMemoryError oome) {
- oom = true;
- }
-
- if (!received || oom) {
- // First stage, always push false.
- checkTimeout(pushTo.offer(Boolean.FALSE, TIMEOUT_VALUE, TimeUnit.MINUTES));
-
- // If we received true, wait for the false to come around.
- if (received) {
- checkTimeout(waitOn.poll(TIMEOUT_VALUE, TimeUnit.MINUTES));
+ // Allocate.
+ try {
+ for (int i = 0; i < MAX_SIZE; i++) {
+ l.add(new ArrayList<Object>(i));
}
-
- // Break out of the loop.
- break;
- } else {
- // Pass on true.
- checkTimeout(pushTo.offer(Boolean.TRUE, TIMEOUT_VALUE, TimeUnit.MINUTES));
- }
+ } catch (OutOfMemoryError oome) {
+ // Fine, we're done.
}
- // We have reached the final point. Wait on the barrier, but at most a minute.
- finalBarrier.await(TIMEOUT_VALUE, TimeUnit.MINUTES);
+ // Atomically increment the counter and check whether we were last.
+ int number = counter.incrementAndGet();
- // Done.
+ if (number < THREAD_COUNT) {
+ // Not last.
+ synchronized (gate) {
+ // Increment the wait counter.
+ waitCount++;
+ gate.wait(TIMEOUT_VALUE * 1000 * 60);
+ }
+ } else {
+ // Last. Wait until waitCount == THREAD_COUNT - 1.
+ for (int loops = 0; ; loops++) {
+ synchronized (gate) {
+ if (waitCount == THREAD_COUNT - 1) {
+ // OK, everyone's waiting. Notify and break out.
+ gate.notifyAll();
+ break;
+ } else if (loops > 40) {
+ // 1s wait, too many tries.
+ System.out.println("Waited too long for the last thread.");
+ System.exit(1);
+ }
+ }
+ // Wait a bit.
+ Thread.sleep(25);
+ }
+ }
+
+ store = null; // Allow GC to reclaim it.
}
}
diff --git a/test/116-nodex2oat/run b/test/116-nodex2oat/run
index 7f90bf7..72488f0 100755
--- a/test/116-nodex2oat/run
+++ b/test/116-nodex2oat/run
@@ -14,6 +14,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+flags="${@}"
+
# Make sure we can run without an oat file,
echo "Run -Xnodex2oat"
${RUN} ${flags} --runtime-option -Xnodex2oat