diff options
-rw-r--r-- | compiler/optimizing/block_builder.cc | 46 | ||||
-rw-r--r-- | compiler/optimizing/block_builder.h | 5 | ||||
-rw-r--r-- | test/570-checker-osr-locals/smali/WeirdLoop.smali | 39 | ||||
-rw-r--r-- | test/570-checker-osr-locals/src/Main.java | 13 |
4 files changed, 103 insertions, 0 deletions
diff --git a/compiler/optimizing/block_builder.cc b/compiler/optimizing/block_builder.cc index a5f78cafe0..e1f061ae70 100644 --- a/compiler/optimizing/block_builder.cc +++ b/compiler/optimizing/block_builder.cc @@ -398,6 +398,48 @@ void HBasicBlockBuilder::InsertTryBoundaryBlocks() { } } +void HBasicBlockBuilder::InsertSynthesizedLoopsForOsr() { + ArenaSet<uint32_t> targets(allocator_->Adapter(kArenaAllocGraphBuilder)); + // Collect basic blocks that are targets of a negative branch. + for (const DexInstructionPcPair& pair : code_item_accessor_) { + const uint32_t dex_pc = pair.DexPc(); + const Instruction& instruction = pair.Inst(); + if (instruction.IsBranch()) { + uint32_t target_dex_pc = dex_pc + instruction.GetTargetOffset(); + if (target_dex_pc < dex_pc) { + HBasicBlock* block = GetBlockAt(target_dex_pc); + CHECK_NE(kNoDexPc, block->GetDexPc()); + targets.insert(block->GetBlockId()); + } + } else if (instruction.IsSwitch()) { + DexSwitchTable table(instruction, dex_pc); + for (DexSwitchTableIterator s_it(table); !s_it.Done(); s_it.Advance()) { + uint32_t target_dex_pc = dex_pc + s_it.CurrentTargetOffset(); + if (target_dex_pc < dex_pc) { + HBasicBlock* block = GetBlockAt(target_dex_pc); + CHECK_NE(kNoDexPc, block->GetDexPc()); + targets.insert(block->GetBlockId()); + } + } + } + } + + // Insert synthesized loops before the collected blocks. + for (uint32_t block_id : targets) { + HBasicBlock* block = graph_->GetBlocks()[block_id]; + HBasicBlock* loop_block = new (allocator_) HBasicBlock(graph_, block->GetDexPc()); + graph_->AddBlock(loop_block); + while (!block->GetPredecessors().empty()) { + block->GetPredecessors()[0]->ReplaceSuccessor(block, loop_block); + } + loop_block->AddSuccessor(loop_block); + loop_block->AddSuccessor(block); + // We loop on false - we know this won't be optimized later on as the loop + // is marked irreducible, which disables loop optimizations. + loop_block->AddInstruction(new (allocator_) HIf(graph_->GetIntConstant(0), kNoDexPc)); + } +} + bool HBasicBlockBuilder::Build() { DCHECK(code_item_accessor_.HasCodeItem()); DCHECK(graph_->GetBlocks().empty()); @@ -413,6 +455,10 @@ bool HBasicBlockBuilder::Build() { ConnectBasicBlocks(); InsertTryBoundaryBlocks(); + if (graph_->IsCompilingOsr()) { + InsertSynthesizedLoopsForOsr(); + } + return true; } diff --git a/compiler/optimizing/block_builder.h b/compiler/optimizing/block_builder.h index 2c1f034d80..42a3f327e7 100644 --- a/compiler/optimizing/block_builder.h +++ b/compiler/optimizing/block_builder.h @@ -59,6 +59,11 @@ class HBasicBlockBuilder : public ValueObject { void ConnectBasicBlocks(); void InsertTryBoundaryBlocks(); + // To ensure branches with negative offsets can always OSR jump to compiled + // code, we insert synthesized loops before each block that is the target of a + // negative branch. + void InsertSynthesizedLoopsForOsr(); + // Helper method which decides whether `catch_block` may have live normal // predecessors and thus whether a synthetic catch block needs to be created // to avoid mixing normal and exceptional predecessors. diff --git a/test/570-checker-osr-locals/smali/WeirdLoop.smali b/test/570-checker-osr-locals/smali/WeirdLoop.smali new file mode 100644 index 0000000000..13cb4f918d --- /dev/null +++ b/test/570-checker-osr-locals/smali/WeirdLoop.smali @@ -0,0 +1,39 @@ +# Copyright (C) 2019 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +.class public LWeirdLoop; + +.super Ljava/lang/Object; + +.method public static weirdLoop()I + .registers 3 + invoke-static {}, LMain;->$noinline$magicValue()I + move-result v0 + const-string v1, "weirdLoop" + invoke-static {v1}, LMain;->isInInterpreter(Ljava/lang/String;)Z + move-result v2 + if-eqz v2, :end + goto :mid + + :top + invoke-static {}, LMain;->$noinline$magicValue()I + move-result v0 + :mid + invoke-static {v1}, LMain;->isInOsrCode(Ljava/lang/String;)Z + move-result v2 + if-eqz v2, :top + :end + return v0 +.end method + diff --git a/test/570-checker-osr-locals/src/Main.java b/test/570-checker-osr-locals/src/Main.java index f4b3ab6af1..c215fa0ab1 100644 --- a/test/570-checker-osr-locals/src/Main.java +++ b/test/570-checker-osr-locals/src/Main.java @@ -19,6 +19,7 @@ public class Main { System.loadLibrary(args[0]); while (runTests(true)); runTests(false); + runSmaliTest(); } public static boolean runTests(boolean warmup) { @@ -65,6 +66,18 @@ public class Main { return true; } + public static void runSmaliTest() { + try { + Class<?> c = Class.forName("WeirdLoop"); + int result = (int) c.getDeclaredMethod("weirdLoop").invoke(null); + if (result != 42) { + throw new Error("Unexpected result: " + result); + } + } catch (Throwable t) { + t.printStackTrace(); + } + } + public static int $noinline$magicValue() { return 42; } |