diff options
-rw-r--r-- | compiler/dex/mir_graph.cc | 3 | ||||
-rw-r--r-- | compiler/dex/mir_graph.h | 3 | ||||
-rw-r--r-- | compiler/dex/mir_optimization.cc | 12 | ||||
-rw-r--r-- | compiler/dex/quick/mir_to_lir.cc | 14 | ||||
-rw-r--r-- | test/109-suspend-check/expected.txt | 7 | ||||
-rw-r--r-- | test/109-suspend-check/info.txt | 2 | ||||
-rw-r--r-- | test/109-suspend-check/src/Main.java | 102 |
7 files changed, 131 insertions, 12 deletions
diff --git a/compiler/dex/mir_graph.cc b/compiler/dex/mir_graph.cc index 86f6ee5..5732dce 100644 --- a/compiler/dex/mir_graph.cc +++ b/compiler/dex/mir_graph.cc @@ -306,6 +306,9 @@ BasicBlock* MIRGraph::ProcessCanBranch(BasicBlock* cur_block, MIR* insn, int cur default: LOG(FATAL) << "Unexpected opcode(" << insn->dalvikInsn.opcode << ") with kBranch set"; } + if (target <= cur_offset) { + insn->backwards_branch = true; + } BasicBlock *taken_block = FindBlock(target, /* split */ true, /* create */ true, /* immed_pred_block_p */ &cur_block); cur_block->taken = taken_block; diff --git a/compiler/dex/mir_graph.h b/compiler/dex/mir_graph.h index 84ab259..45e425b 100644 --- a/compiler/dex/mir_graph.h +++ b/compiler/dex/mir_graph.h @@ -232,7 +232,8 @@ struct SSARepresentation { */ struct MIR { DecodedInstruction dalvikInsn; - unsigned int width; + uint16_t width; + bool backwards_branch; // TODO: may be useful to make this an attribute flag word. unsigned int offset; int m_unit_index; // From which method was this MIR included MIR* prev; diff --git a/compiler/dex/mir_optimization.cc b/compiler/dex/mir_optimization.cc index a6314f4..82ba6e3 100644 --- a/compiler/dex/mir_optimization.cc +++ b/compiler/dex/mir_optimization.cc @@ -153,7 +153,14 @@ static BasicBlock* NextDominatedBlock(BasicBlock* bb) { } DCHECK((bb->block_type == kEntryBlock) || (bb->block_type == kDalvikByteCode) || (bb->block_type == kExitBlock)); - bb = bb->fall_through; + if (((bb->taken != NULL) && (bb->fall_through == NULL)) && + ((bb->taken->block_type == kDalvikByteCode) || (bb->taken->block_type == kExitBlock))) { + // Follow simple unconditional branches. + bb = bb->taken; + } else { + // Follow simple fallthrough + bb = (bb->taken != NULL) ? NULL : bb->fall_through; + } if (bb == NULL || (Predecessors(bb) != 1)) { return NULL; } @@ -303,7 +310,8 @@ bool MIRGraph::BasicBlockOpt(BasicBlock* bb) { case Instruction::IF_GEZ: case Instruction::IF_GTZ: case Instruction::IF_LEZ: - if (bb->taken->dominates_return) { + // If we've got a backwards branch to return, no need to suspend check. + if ((bb->taken->dominates_return) && (mir->backwards_branch)) { mir->optimization_flags |= MIR_IGNORE_SUSPEND_CHECK; if (cu_->verbose) { LOG(INFO) << "Suppressed suspend check on branch to return at 0x" << std::hex << mir->offset; diff --git a/compiler/dex/quick/mir_to_lir.cc b/compiler/dex/quick/mir_to_lir.cc index 74eaa66..8f42999 100644 --- a/compiler/dex/quick/mir_to_lir.cc +++ b/compiler/dex/quick/mir_to_lir.cc @@ -239,7 +239,7 @@ void Mir2Lir::CompileDalvikInstruction(MIR* mir, BasicBlock* bb, LIR* label_list case Instruction::GOTO: case Instruction::GOTO_16: case Instruction::GOTO_32: - if (bb->taken->start_offset <= mir->offset) { + if (mir->backwards_branch) { GenSuspendTestAndBranch(opt_flags, &label_list[bb->taken->id]); } else { OpUnconditionalBranch(&label_list[bb->taken->id]); @@ -273,19 +273,17 @@ void Mir2Lir::CompileDalvikInstruction(MIR* mir, BasicBlock* bb, LIR* label_list case Instruction::IF_LE: { LIR* taken = &label_list[bb->taken->id]; LIR* fall_through = &label_list[bb->fall_through->id]; - bool backward_branch; - backward_branch = (bb->taken->start_offset <= mir->offset); // Result known at compile time? if (rl_src[0].is_const && rl_src[1].is_const) { bool is_taken = EvaluateBranch(opcode, mir_graph_->ConstantValue(rl_src[0].orig_sreg), mir_graph_->ConstantValue(rl_src[1].orig_sreg)); - if (is_taken && backward_branch) { + if (is_taken && mir->backwards_branch) { GenSuspendTest(opt_flags); } int id = is_taken ? bb->taken->id : bb->fall_through->id; OpUnconditionalBranch(&label_list[id]); } else { - if (backward_branch) { + if (mir->backwards_branch) { GenSuspendTest(opt_flags); } GenCompareAndBranch(opcode, rl_src[0], rl_src[1], taken, @@ -302,18 +300,16 @@ void Mir2Lir::CompileDalvikInstruction(MIR* mir, BasicBlock* bb, LIR* label_list case Instruction::IF_LEZ: { LIR* taken = &label_list[bb->taken->id]; LIR* fall_through = &label_list[bb->fall_through->id]; - bool backward_branch; - backward_branch = (bb->taken->start_offset <= mir->offset); // Result known at compile time? if (rl_src[0].is_const) { bool is_taken = EvaluateBranch(opcode, mir_graph_->ConstantValue(rl_src[0].orig_sreg), 0); - if (is_taken && backward_branch) { + if (is_taken && mir->backwards_branch) { GenSuspendTest(opt_flags); } int id = is_taken ? bb->taken->id : bb->fall_through->id; OpUnconditionalBranch(&label_list[id]); } else { - if (backward_branch) { + if (mir->backwards_branch) { GenSuspendTest(opt_flags); } GenCompareZeroAndBranch(opcode, rl_src[0], taken, fall_through); diff --git a/test/109-suspend-check/expected.txt b/test/109-suspend-check/expected.txt new file mode 100644 index 0000000..07cc825 --- /dev/null +++ b/test/109-suspend-check/expected.txt @@ -0,0 +1,7 @@ +Running (5 seconds) ... +. +. +. +. +. +Done. diff --git a/test/109-suspend-check/info.txt b/test/109-suspend-check/info.txt new file mode 100644 index 0000000..d89d66a --- /dev/null +++ b/test/109-suspend-check/info.txt @@ -0,0 +1,2 @@ +To support garbage collection, debugging and profiling the VM must be able to send all threads +to a safepoint. This tests the ability of the VM to do this for a tight loop. diff --git a/test/109-suspend-check/src/Main.java b/test/109-suspend-check/src/Main.java new file mode 100644 index 0000000..d92b9e5 --- /dev/null +++ b/test/109-suspend-check/src/Main.java @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +public class Main { + private static final int TEST_TIME = 5; + + public static void main(String[] args) { + System.out.println("Running (" + TEST_TIME + " seconds) ..."); + InfiniteForLoop forLoop = new InfiniteForLoop(); + InfiniteWhileLoop whileLoop = new InfiniteWhileLoop(); + InfiniteDoWhileLoop doWhileLoop = new InfiniteDoWhileLoop(); + MakeGarbage garbage = new MakeGarbage(); + forLoop.start(); + whileLoop.start(); + doWhileLoop.start(); + garbage.start(); + for (int i = 0; i < TEST_TIME; i++) { + System.gc(); + System.out.println("."); + sleep(1000); + } + forLoop.stopNow(); + whileLoop.stopNow(); + doWhileLoop.stopNow(); + garbage.stopNow(); + System.out.println("Done."); + } + + public static void sleep(int ms) { + try { + Thread.sleep(ms); + } catch (InterruptedException ie) { + System.err.println("sleep was interrupted"); + } + } +} + +class InfiniteWhileLoop extends Thread { + volatile private boolean keepGoing = true; + public void run() { + int i = 0; + while (keepGoing) { + i++; + } + } + public void stopNow() { + keepGoing = false; + } +} + +class InfiniteDoWhileLoop extends Thread { + volatile private boolean keepGoing = true; + public void run() { + int i = 0; + do { + i++; + } while (keepGoing); + } + public void stopNow() { + keepGoing = false; + } +} + +class InfiniteForLoop extends Thread { + int count = 100000; + volatile private boolean keepGoing = true; + public void run() { + int i = 0; + for (int j = 0; keepGoing; j++) { + i += j; + } + } + public void stopNow() { + keepGoing = false; + } +} + + +class MakeGarbage extends Thread { + volatile private boolean keepGoing = true; + public void run() { + while (keepGoing) { + byte[] garbage = new byte[100000]; + } + } + public void stopNow() { + keepGoing = false; + } +} |