diff options
| -rwxr-xr-x | compiler/dex/quick/gen_invoke.cc | 30 | ||||
| -rwxr-xr-x | compiler/dex/quick/x86/fp_x86.cc | 18 | ||||
| -rwxr-xr-x | compiler/dex/quick/x86/int_x86.cc | 18 | ||||
| -rw-r--r-- | compiler/optimizing/graph_checker.cc | 341 | ||||
| -rw-r--r-- | compiler/optimizing/graph_checker.h | 5 | ||||
| -rw-r--r-- | patchoat/patchoat.cc | 26 | ||||
| -rw-r--r-- | runtime/arch/instruction_set.cc | 25 | ||||
| -rw-r--r-- | runtime/arch/instruction_set.h | 2 | ||||
| -rw-r--r-- | runtime/elf_file.cc | 30 | ||||
| -rw-r--r-- | runtime/gc/accounting/card_table-inl.h | 11 | ||||
| -rw-r--r-- | runtime/gc/accounting/card_table.h | 2 | ||||
| -rw-r--r-- | runtime/gc/collector/mark_sweep.cc | 26 | ||||
| -rw-r--r-- | runtime/gc/heap.cc | 4 | ||||
| -rw-r--r-- | runtime/monitor.cc | 5 | ||||
| -rw-r--r-- | runtime/primitive.cc | 5 | ||||
| -rw-r--r-- | runtime/primitive.h | 2 | ||||
| -rw-r--r-- | test/082-inline-execute/src/Main.java | 58 | ||||
| -rw-r--r-- | test/114-ParallelGC/src/Main.java | 171 | ||||
| -rwxr-xr-x | test/116-nodex2oat/run | 2 |
19 files changed, 421 insertions, 360 deletions
diff --git a/compiler/dex/quick/gen_invoke.cc b/compiler/dex/quick/gen_invoke.cc index 2a6dfefe22..d5889f5b48 100755 --- a/compiler/dex/quick/gen_invoke.cc +++ b/compiler/dex/quick/gen_invoke.cc @@ -1048,9 +1048,13 @@ bool Mir2Lir::GenInlinedReverseBytes(CallInfo* info, OpSize size) { // 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::GenInlinedReverseBytes(CallInfo* info, OpSize size) { } 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::GenInlinedAbsInt(CallInfo* info) { } 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 @@ bool Mir2Lir::GenInlinedFloatCvt(CallInfo* info) { // 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 @@ bool Mir2Lir::GenInlinedDoubleCvt(CallInfo* info) { // 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 4825db6402..89c5648d0a 100755 --- a/compiler/dex/quick/x86/fp_x86.cc +++ b/compiler/dex/quick/x86/fp_x86.cc @@ -599,8 +599,12 @@ void X86Mir2Lir::GenNegDouble(RegLocation rl_dest, RegLocation rl_src) { } 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::GenInlinedAbsDouble(CallInfo* info) { 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 @@ bool X86Mir2Lir::GenInlinedMinMaxFP(CallInfo* info, bool is_min, bool is_double) 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 ba9c611e9b..03156dc5ad 100755 --- a/compiler/dex/quick/x86/int_x86.cc +++ b/compiler/dex/quick/x86/int_x86.cc @@ -948,12 +948,16 @@ bool X86Mir2Lir::GenInlinedMinMax(CallInfo* info, bool is_min, bool is_long) { } // 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::GenInlinedMinMax(CallInfo* info, bool is_min, bool is_long) { } 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 @@ bool X86Mir2Lir::GenInlinedPeek(CallInfo* info, OpSize size) { } 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 @@ void X86Mir2Lir::SwapBits64(RegStorage result_reg, int shift, int64_t value) { } 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 291b14cb52..4d74c4e936 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 @@ void GraphChecker::VisitBasicBlock(HBasicBlock* block) { } } 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 @@ void GraphChecker::VisitBasicBlock(HBasicBlock* block) { } } 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 @@ void GraphChecker::VisitBasicBlock(HBasicBlock* block) { 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::VisitBasicBlock(HBasicBlock* block) { 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 @@ void GraphChecker::VisitInstruction(HInstruction* instruction) { ? 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 @@ void GraphChecker::VisitInstruction(HInstruction* instruction) { ? 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 @@ void SSAChecker::VisitBasicBlock(HBasicBlock* block) { 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 @@ void SSAChecker::CheckLoop(HBasicBlock* loop_header) { // 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 @@ void SSAChecker::CheckLoop(HBasicBlock* loop_header) { 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 @@ void SSAChecker::VisitInstruction(HInstruction* instruction) { !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 @@ void SSAChecker::VisitInstruction(HInstruction* instruction) { 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 @@ void SSAChecker::VisitPhi(HPhi* phi) { // 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 @@ void SSAChecker::VisitPhi(HPhi* phi) { 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 @@ void SSAChecker::VisitIf(HIf* instruction) { 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 @@ void SSAChecker::VisitBinaryOperation(HBinaryOperation* op) { 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 ae1557b57c..5ec3003ac8 100644 --- a/compiler/optimizing/graph_checker.h +++ b/compiler/optimizing/graph_checker.h @@ -60,6 +60,11 @@ class GraphChecker : public HGraphDelegateVisitor { } 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 6c86c7b7a5..2059a96c70 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 @@ bool PatchOat::Patch(File* input_oat, const std::string& image_location, off_t d 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 5ab461bc73..81ca010423 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 @@ InstructionSet GetInstructionSetFromString(const char* isa_str) { 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 9135e58c1a..9cfd2eb2d6 100644 --- a/runtime/arch/instruction_set.h +++ b/runtime/arch/instruction_set.h @@ -80,6 +80,8 @@ const char* GetInstructionSetString(InstructionSet isa); // 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 1b91aa64d2..a22e2741ce 100644 --- a/runtime/elf_file.cc +++ b/runtime/elf_file.cc @@ -1313,35 +1313,7 @@ bool ElfFileImpl<Elf_Ehdr, Elf_Phdr, Elf_Shdr, Elf_Word, 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 15562e506e..83ad33e145 100644 --- a/runtime/gc/accounting/card_table-inl.h +++ b/runtime/gc/accounting/card_table-inl.h @@ -48,7 +48,7 @@ static inline bool byte_cas(uint8_t old_value, uint8_t new_value, uint8_t* addre #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 @@ inline size_t CardTable::Scan(ContinuousSpaceBitmap* bitmap, uint8_t* scan_begin 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 @@ inline size_t CardTable::Scan(ContinuousSpaceBitmap* bitmap, uint8_t* scan_begin << "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 @@ inline size_t CardTable::Scan(ContinuousSpaceBitmap* bitmap, uint8_t* scan_begin 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 9bd3fbaf7a..a84cf34300 100644 --- a/runtime/gc/accounting/card_table.h +++ b/runtime/gc/accounting/card_table.h @@ -101,7 +101,7 @@ class CardTable { // 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 80f7968ef9..04fb6941ba 100644 --- a/runtime/gc/collector/mark_sweep.cc +++ b/runtime/gc/collector/mark_sweep.cc @@ -687,12 +687,12 @@ class CardScanTask : public MarkStackTask<false> { 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 @@ class CardScanTask : public MarkStackTask<false> { 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 @@ class CardScanTask : public MarkStackTask<false> { 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 @@ void MarkSweep::ScanGrayObjects(bool paused, uint8_t minimum_age) { // 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 @@ void MarkSweep::ScanGrayObjects(bool paused, uint8_t minimum_age) { // 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 @@ void MarkSweep::ScanGrayObjects(bool paused, uint8_t minimum_age) { } 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 eed93524ef..6ba30c6580 100644 --- a/runtime/gc/heap.cc +++ b/runtime/gc/heap.cc @@ -2385,8 +2385,8 @@ class VerifyReferenceVisitor { // 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 ef63080649..5e3338042c 100644 --- a/runtime/monitor.cc +++ b/runtime/monitor.cc @@ -933,8 +933,11 @@ void Monitor::DescribeWait(std::ostream& os, const Thread* thread) { 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 a639f93f45..d29a06043a 100644 --- a/runtime/primitive.cc +++ b/runtime/primitive.cc @@ -31,6 +31,11 @@ static const char* kTypeNames[] = { "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 afcc64ded3..50d171c908 100644 --- a/runtime/primitive.h +++ b/runtime/primitive.h @@ -146,6 +146,8 @@ class Primitive { } } + 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 862fe066ce..a737ccdb79 100644 --- a/test/082-inline-execute/src/Main.java +++ b/test/082-inline-execute/src/Main.java @@ -34,6 +34,7 @@ public class Main { 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 @@ public class Main { 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 class Main { } 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 class Main { } 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 class Main { } 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 class Main { } 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 class Main { } 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 class Main { } 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 class Main { } 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 class Main { } 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 class Main { } 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 class Main { } 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 @@ public class Main { 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 class Main { } 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 class Main { } 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 class Main { } 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 class Main { } 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 class Main { } 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 class Main { } 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 class Main { } 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 class Main { } 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 class Main { } 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 class Main { } 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 class Main { } 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 class Main { } 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 class Main { } 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 class Main { } 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 @@ public class Main { 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 class Main { } 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 class Main { } 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 class Main { } 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 class Main { } 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 class Main { } 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 class Main { } 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 class Main { } 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 class Main { } 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 class Main { } 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 class Main { } 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 class Main { } 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 class Main { } 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 class Main { } 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 @@ public class Main { 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 @@ public class Main { 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 @@ public class Main { 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 48f9bd363f..df2243c27f 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]; - - // 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>()); - } + Thread[] threads = new Thread[THREAD_COUNT]; + + // 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 @@ public class Main implements Runnable { // 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 static void checkTimeout(boolean b) { - if (!b) { - // Something went wrong. - System.out.println("Bad things happened, timeout."); - System.exit(1); - } + private Main(CyclicBarrier startBarrier) { + this.startBarrier = startBarrier; } - 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; - - // 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)); - } + // Wait for the start signal. + startBarrier.await(TIMEOUT_VALUE, java.util.concurrent.TimeUnit.MINUTES); - // Break out of the loop. - break; - } else { - // Pass on true. - checkTimeout(pushTo.offer(Boolean.TRUE, TIMEOUT_VALUE, TimeUnit.MINUTES)); - } + // Allocate. + try { + for (int i = 0; i < MAX_SIZE; i++) { + l.add(new ArrayList<Object>(i)); + } + } 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(); + + 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); + } + } - // Done. + store = null; // Allow GC to reclaim it. } } diff --git a/test/116-nodex2oat/run b/test/116-nodex2oat/run index 7f90bf746d..72488f0da3 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 |