diff options
author | 2015-08-20 17:47:48 +0100 | |
---|---|---|
committer | 2015-09-14 20:42:58 +0100 | |
commit | b022fa1300e6d78639b3b910af0cf85c43df44bb (patch) | |
tree | 780c7d6bdee784c2f8248979de348491cfb63b34 /compiler/optimizing/optimizing_compiler.cc | |
parent | e481c006e8b055a31d9c7cff27f4145e57e3c113 (diff) |
ART: Register allocation and runtime support for try/catch
This patch completes a series of CLs that add support for try/catch
in the Optimizing compiler. With it, Optimizing can compile all
methods containing try/catch, provided they don't contain catch loops.
Future work will focus on improving performance of the generated code.
SsaLivenessAnalysis was updated to propagate liveness information of
instructions live at catch blocks, and to keep location information on
instructions which may be caught by catch phis.
RegisterAllocator was extended to spill values used after catch, and
to allocate spill slots for catch phis. Catch phis generated for the
same vreg share a spill slot as the raw value must be the same.
Location builders and slow paths were updated to reflect the fact that
throwing an exception may not lead to escaping the method.
Instruction code generators are forbidden from using of implicit null
checks in try blocks as live registers need to be saved before handing
over to the runtime.
CodeGenerator emits a stack map for each catch block, storing locations
of catch phis. CodeInfo and StackMapStream recognize this new type of
stack map and store them separate from other stack maps to avoid dex_pc
conflicts.
After having found the target catch block to deliver an exception to,
QuickExceptionHandler looks up the dex register maps at the throwing
instruction and the catch block and copies the values over to their
respective locations.
The runtime-support approach was selected because it allows for the
best performance in the normal control-flow path, since no propagation
of catch phi values is necessary until the exception is thrown. In
addition, it also greatly simplifies the register allocation phase.
ConstantHoisting was removed from LICMTest because it instantiated
(now abstract) HConstant and was bogus anyway (constants are always in
the entry block).
Change-Id: Ie31038ad8e3ee0c13a5bbbbaf5f0b3e532310e4e
Diffstat (limited to 'compiler/optimizing/optimizing_compiler.cc')
-rw-r--r-- | compiler/optimizing/optimizing_compiler.cc | 64 |
1 files changed, 34 insertions, 30 deletions
diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc index f549ba8391..0099b21343 100644 --- a/compiler/optimizing/optimizing_compiler.cc +++ b/compiler/optimizing/optimizing_compiler.cc @@ -485,34 +485,43 @@ static void RunOptimizations(HGraph* graph, RunOptimizations(optimizations1, arraysize(optimizations1), pass_observer); + // TODO: Update passes incompatible with try/catch so we have the same + // pipeline for all methods. if (graph->HasTryCatch()) { - // TODO: Update the optimizations below to work correctly under try/catch - // semantics. The optimizations above suffice for running codegen - // in the meanwhile. - return; + HOptimization* optimizations2[] = { + side_effects, + gvn, + dce2, + // The codegen has a few assumptions that only the instruction simplifier + // can satisfy. For example, the code generator does not expect to see a + // HTypeConversion from a type to the same type. + simplify4, + }; + + RunOptimizations(optimizations2, arraysize(optimizations2), pass_observer); + } else { + MaybeRunInliner(graph, driver, stats, dex_compilation_unit, pass_observer, handles); + + HOptimization* optimizations2[] = { + // BooleanSimplifier depends on the InstructionSimplifier removing + // redundant suspend checks to recognize empty blocks. + boolean_simplify, + fold2, // TODO: if we don't inline we can also skip fold2. + side_effects, + gvn, + licm, + bce, + simplify3, + dce2, + // The codegen has a few assumptions that only the instruction simplifier + // can satisfy. For example, the code generator does not expect to see a + // HTypeConversion from a type to the same type. + simplify4, + }; + + RunOptimizations(optimizations2, arraysize(optimizations2), pass_observer); } - MaybeRunInliner(graph, driver, stats, dex_compilation_unit, pass_observer, handles); - - HOptimization* optimizations2[] = { - // BooleanSimplifier depends on the InstructionSimplifier removing redundant - // suspend checks to recognize empty blocks. - boolean_simplify, - fold2, // TODO: if we don't inline we can also skip fold2. - side_effects, - gvn, - licm, - bce, - simplify3, - dce2, - // The codegen has a few assumptions that only the instruction simplifier can - // satisfy. For example, the code generator does not expect to see a - // HTypeConversion from a type to the same type. - simplify4, - }; - - RunOptimizations(optimizations2, arraysize(optimizations2), pass_observer); - RunArchOptimizations(driver->GetInstructionSet(), graph, stats, pass_observer); } @@ -566,11 +575,6 @@ CompiledMethod* OptimizingCompiler::CompileOptimized(HGraph* graph, RunOptimizations(graph, compiler_driver, compilation_stats_.get(), dex_compilation_unit, pass_observer, &handles); - if (graph->HasTryCatch()) { - soa.Self()->TransitionFromSuspendedToRunnable(); - return nullptr; - } - AllocateRegisters(graph, codegen, pass_observer); ArenaAllocator* arena = graph->GetArena(); |