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-- | compiler/driver/compiler_driver.cc | 14 | ||||
| -rw-r--r-- | runtime/thread.cc | 3 | ||||
| -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 |
9 files changed, 140 insertions, 20 deletions
diff --git a/compiler/dex/mir_graph.cc b/compiler/dex/mir_graph.cc index 86f6ee5cbd..5732dce561 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 84ab2590b0..45e425b32d 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 a6314f4cab..82ba6e3240 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 74eaa661a8..8f42999a04 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/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc index a0a5c0160d..120f232d7a 100644 --- a/compiler/driver/compiler_driver.cc +++ b/compiler/driver/compiler_driver.cc @@ -1946,14 +1946,14 @@ static const char* class_initializer_black_list[] = { "Ljava/util/Scanner;", // regex.Pattern.compileImpl. "Ljava/util/SimpleTimeZone;", // Sub-class of TimeZone. "Ljava/util/TimeZone;", // Calls regex.Pattern.compile -..-> regex.Pattern.compileImpl. - "Ljava/util/concurrent/ConcurrentHashMap$Segment;", // Calls Runtime.getRuntime().availableProcessors(). - "Ljava/util/concurrent/ConcurrentSkipListMap;", // Calls OsConstants.initConstants. - "Ljava/util/concurrent/Exchanger;", // Calls OsConstants.initConstants. - "Ljava/util/concurrent/ForkJoinPool;", // Calls OsConstants.initConstants. - "Ljava/util/concurrent/LinkedTransferQueue;", // Calls OsConstants.initConstants. - "Ljava/util/concurrent/Phaser;", // Calls OsConstants.initConstants. + "Ljava/util/concurrent/ConcurrentHashMap;", // Calls Runtime.getRuntime().availableProcessors(). + "Ljava/util/concurrent/ConcurrentSkipListMap;", // Calls Random() -> OsConstants.initConstants. + "Ljava/util/concurrent/Exchanger;", // Calls Runtime.getRuntime().availableProcessors(). + "Ljava/util/concurrent/ForkJoinPool;", // Makes a thread pool ..-> calls OsConstants.initConstants. + "Ljava/util/concurrent/LinkedTransferQueue;", // Calls Runtime.getRuntime().availableProcessors(). + "Ljava/util/concurrent/Phaser;", // Calls Runtime.getRuntime().availableProcessors(). "Ljava/util/concurrent/ScheduledThreadPoolExecutor;", // Calls AtomicLong.VMSupportsCS8() - "Ljava/util/concurrent/SynchronousQueue;", // Calls OsConstants.initConstants. + "Ljava/util/concurrent/SynchronousQueue;", // Calls Runtime.getRuntime().availableProcessors(). "Ljava/util/concurrent/atomic/AtomicLong;", // Calls AtomicLong.VMSupportsCS8() "Ljava/util/logging/LogManager;", // Calls System.getProperty -> OsConstants.initConstants. "Ljava/util/prefs/AbstractPreferences;", // Calls OsConstants.initConstants. diff --git a/runtime/thread.cc b/runtime/thread.cc index 8fc744d263..505e368ec0 100644 --- a/runtime/thread.cc +++ b/runtime/thread.cc @@ -876,7 +876,8 @@ void Thread::DumpStack(std::ostream& os) const { // TODO: we call this code when dying but may not have suspended the thread ourself. The // IsSuspended check is therefore racy with the use for dumping (normally we inhibit // the race with the thread_suspend_count_lock_). - bool dump_for_abort = (gAborting > 0); + // No point dumping for an abort in debug builds where we'll hit the not suspended check in stack. + bool dump_for_abort = (gAborting > 0) && !kIsDebugBuild; if (this == Thread::Current() || IsSuspended() || dump_for_abort) { // If we're currently in native code, dump that stack before dumping the managed stack. if (dump_for_abort || ShouldShowNativeStack(this)) { diff --git a/test/109-suspend-check/expected.txt b/test/109-suspend-check/expected.txt new file mode 100644 index 0000000000..07cc8253da --- /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 0000000000..d89d66aeda --- /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 0000000000..d92b9e5070 --- /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; + } +} |