diff options
author | Calin Juravle <calin@google.com> | 2015-04-30 19:28:21 +0100 |
---|---|---|
committer | Calin Juravle <calin@google.com> | 2015-05-01 14:23:32 +0100 |
commit | 702d26018769f9fbc4763c7ed02331aed596ac7d (patch) | |
tree | 74578ce3cb0abfd2e25c53d7272415c82717e035 /compiler/optimizing | |
parent | fd5f56d4604eeeacdf6be5189187b6ef49157280 (diff) | |
download | android_art-702d26018769f9fbc4763c7ed02331aed596ac7d.tar.gz android_art-702d26018769f9fbc4763c7ed02331aed596ac7d.tar.bz2 android_art-702d26018769f9fbc4763c7ed02331aed596ac7d.zip |
Skip compilation when falling-through out of method code.
Bug: 19988134
Change-Id: I68638ce9551848a67af587595f264b51f976df11
Diffstat (limited to 'compiler/optimizing')
-rw-r--r-- | compiler/optimizing/builder.cc | 24 | ||||
-rw-r--r-- | compiler/optimizing/builder.h | 5 | ||||
-rw-r--r-- | compiler/optimizing/optimizing_compiler_stats.h | 44 |
3 files changed, 47 insertions, 26 deletions
diff --git a/compiler/optimizing/builder.cc b/compiler/optimizing/builder.cc index 0f44af07b8..a5c6f23343 100644 --- a/compiler/optimizing/builder.cc +++ b/compiler/optimizing/builder.cc @@ -282,7 +282,10 @@ bool HGraphBuilder::BuildGraph(const DexFile::CodeItem& code_item) { // To avoid splitting blocks, we compute ahead of time the instructions that // start a new block, and create these blocks. - ComputeBranchTargets(code_ptr, code_end, &number_of_branches); + if (!ComputeBranchTargets(code_ptr, code_end, &number_of_branches)) { + MaybeRecordStat(MethodCompilationStat::kNotCompiledBranchOutsideMethodCode); + return false; + } // Note that the compiler driver is null when unit testing. if ((compiler_driver_ != nullptr) && SkipCompilation(code_item, number_of_branches)) { @@ -349,7 +352,7 @@ void HGraphBuilder::MaybeUpdateCurrentBlock(size_t index) { current_block_ = block; } -void HGraphBuilder::ComputeBranchTargets(const uint16_t* code_ptr, +bool HGraphBuilder::ComputeBranchTargets(const uint16_t* code_ptr, const uint16_t* code_end, size_t* number_of_branches) { branch_targets_.SetSize(code_end - code_ptr); @@ -374,7 +377,14 @@ void HGraphBuilder::ComputeBranchTargets(const uint16_t* code_ptr, } dex_pc += instruction.SizeInCodeUnits(); code_ptr += instruction.SizeInCodeUnits(); - if ((code_ptr < code_end) && (FindBlockStartingAt(dex_pc) == nullptr)) { + + if (code_ptr >= code_end) { + if (instruction.CanFlowThrough()) { + // In the normal case we should never hit this but someone can artificially forge a dex + // file to fall-through out the method code. In this case we bail out compilation. + return false; + } + } else if (FindBlockStartingAt(dex_pc) == nullptr) { block = new (arena_) HBasicBlock(graph_, dex_pc); branch_targets_.Put(dex_pc, block); } @@ -406,7 +416,12 @@ void HGraphBuilder::ComputeBranchTargets(const uint16_t* code_ptr, // Fall-through. Add a block if there is more code afterwards. dex_pc += instruction.SizeInCodeUnits(); code_ptr += instruction.SizeInCodeUnits(); - if ((code_ptr < code_end) && (FindBlockStartingAt(dex_pc) == nullptr)) { + if (code_ptr >= code_end) { + // In the normal case we should never hit this but someone can artificially forge a dex + // file to fall-through out the method code. In this case we bail out compilation. + // (A switch can fall-through so we don't need to check CanFlowThrough().) + return false; + } else if (FindBlockStartingAt(dex_pc) == nullptr) { block = new (arena_) HBasicBlock(graph_, dex_pc); branch_targets_.Put(dex_pc, block); } @@ -415,6 +430,7 @@ void HGraphBuilder::ComputeBranchTargets(const uint16_t* code_ptr, dex_pc += instruction.SizeInCodeUnits(); } } + return true; } HBasicBlock* HGraphBuilder::FindBlockStartingAt(int32_t index) const { diff --git a/compiler/optimizing/builder.h b/compiler/optimizing/builder.h index dc6d97eb0c..36503ce43a 100644 --- a/compiler/optimizing/builder.h +++ b/compiler/optimizing/builder.h @@ -88,7 +88,10 @@ class HGraphBuilder : public ValueObject { // the newly created blocks. // As a side effect, also compute the number of dex instructions, blocks, and // branches. - void ComputeBranchTargets(const uint16_t* start, + // Returns true if all the branches fall inside the method code, false otherwise. + // (In normal cases this should always return true but someone can artificially + // create a code unit in which branches fall-through out of it). + bool ComputeBranchTargets(const uint16_t* start, const uint16_t* end, size_t* number_of_branches); void MaybeUpdateCurrentBlock(size_t index); diff --git a/compiler/optimizing/optimizing_compiler_stats.h b/compiler/optimizing/optimizing_compiler_stats.h index 65c84e6942..b6b1bb1cad 100644 --- a/compiler/optimizing/optimizing_compiler_stats.h +++ b/compiler/optimizing/optimizing_compiler_stats.h @@ -29,25 +29,26 @@ enum MethodCompilationStat { kCompiledBaseline, kCompiledOptimized, kCompiledQuick, - kInstructionSimplifications, kInlinedInvoke, - kNotCompiledUnsupportedIsa, - kNotCompiledPathological, + kInstructionSimplifications, + kNotCompiledBranchOutsideMethodCode, + kNotCompiledCannotBuildSSA, + kNotCompiledCantAccesType, + kNotCompiledClassNotVerified, kNotCompiledHugeMethod, kNotCompiledLargeMethodNoBranches, - kNotCompiledCannotBuildSSA, kNotCompiledNoCodegen, - kNotCompiledUnresolvedMethod, - kNotCompiledUnresolvedField, kNotCompiledNonSequentialRegPair, + kNotCompiledPathological, kNotCompiledSpaceFilter, - kNotOptimizedTryCatch, - kNotOptimizedDisabled, - kNotCompiledCantAccesType, - kNotOptimizedRegisterAllocator, kNotCompiledUnhandledInstruction, + kNotCompiledUnresolvedField, + kNotCompiledUnresolvedMethod, + kNotCompiledUnsupportedIsa, kNotCompiledVerifyAtRuntime, - kNotCompiledClassNotVerified, + kNotOptimizedDisabled, + kNotOptimizedRegisterAllocator, + kNotOptimizedTryCatch, kRemovedCheckedCast, kRemovedDeadInstruction, kRemovedNullCheck, @@ -98,23 +99,24 @@ class OptimizingCompilerStats { case kCompiledQuick : return "kCompiledQuick"; case kInlinedInvoke : return "kInlinedInvoke"; case kInstructionSimplifications: return "kInstructionSimplifications"; - case kNotCompiledUnsupportedIsa : return "kNotCompiledUnsupportedIsa"; - case kNotCompiledPathological : return "kNotCompiledPathological"; + case kNotCompiledBranchOutsideMethodCode: return "kNotCompiledBranchOutsideMethodCode"; + case kNotCompiledCannotBuildSSA : return "kNotCompiledCannotBuildSSA"; + case kNotCompiledCantAccesType : return "kNotCompiledCantAccesType"; + case kNotCompiledClassNotVerified : return "kNotCompiledClassNotVerified"; case kNotCompiledHugeMethod : return "kNotCompiledHugeMethod"; case kNotCompiledLargeMethodNoBranches : return "kNotCompiledLargeMethodNoBranches"; - case kNotCompiledCannotBuildSSA : return "kNotCompiledCannotBuildSSA"; case kNotCompiledNoCodegen : return "kNotCompiledNoCodegen"; - case kNotCompiledUnresolvedMethod : return "kNotCompiledUnresolvedMethod"; - case kNotCompiledUnresolvedField : return "kNotCompiledUnresolvedField"; case kNotCompiledNonSequentialRegPair : return "kNotCompiledNonSequentialRegPair"; - case kNotOptimizedDisabled : return "kNotOptimizedDisabled"; - case kNotOptimizedTryCatch : return "kNotOptimizedTryCatch"; - case kNotCompiledCantAccesType : return "kNotCompiledCantAccesType"; + case kNotCompiledPathological : return "kNotCompiledPathological"; case kNotCompiledSpaceFilter : return "kNotCompiledSpaceFilter"; - case kNotOptimizedRegisterAllocator : return "kNotOptimizedRegisterAllocator"; case kNotCompiledUnhandledInstruction : return "kNotCompiledUnhandledInstruction"; + case kNotCompiledUnresolvedField : return "kNotCompiledUnresolvedField"; + case kNotCompiledUnresolvedMethod : return "kNotCompiledUnresolvedMethod"; + case kNotCompiledUnsupportedIsa : return "kNotCompiledUnsupportedIsa"; case kNotCompiledVerifyAtRuntime : return "kNotCompiledVerifyAtRuntime"; - case kNotCompiledClassNotVerified : return "kNotCompiledClassNotVerified"; + case kNotOptimizedDisabled : return "kNotOptimizedDisabled"; + case kNotOptimizedRegisterAllocator : return "kNotOptimizedRegisterAllocator"; + case kNotOptimizedTryCatch : return "kNotOptimizedTryCatch"; case kRemovedCheckedCast: return "kRemovedCheckedCast"; case kRemovedDeadInstruction: return "kRemovedDeadInstruction"; case kRemovedNullCheck: return "kRemovedNullCheck"; |