}
void HDeadCodeElimination::Run() {
- RemoveDeadBlocks();
+ if (!graph_->HasTryCatch()) {
+ // TODO: Update dead block elimination and enable for try/catch.
+ RemoveDeadBlocks();
+ }
SsaRedundantPhiElimination(graph_).Run();
RemoveDeadInstructions();
}
}
}
+bool HGraph::HasTryCatch() const {
+ for (size_t i = 0, e = blocks_.Size(); i < e; ++i) {
+ HBasicBlock* block = blocks_.Get(i);
+ if (block != nullptr && (block->IsTryBlock() || block->IsCatchBlock())) {
+ return true;
+ }
+ }
+ return false;
+}
+
void HGraph::SimplifyCFG() {
// Simplify the CFG for future analysis, and code generation:
// (1): Split critical edges.
return instruction_set_;
}
+ // TODO: Remove once the full compilation pipeline is enabled for try/catch.
+ bool HasTryCatch() const;
+
private:
void VisitBlockForDominatorTree(HBasicBlock* block,
HBasicBlock* predecessor,
public:
HLoadException() : HExpression(Primitive::kPrimNot, SideEffects::None()) {}
+ bool CanBeNull() const OVERRIDE { return false; }
+
DECLARE_INSTRUCTION(LoadException);
private:
|| instruction_set == kX86_64;
}
-static bool CanOptimize(const DexFile::CodeItem& code_item) {
- // TODO: We currently cannot optimize methods with try/catch.
- return code_item.tries_size_ == 0;
-}
-
static void RunOptimizations(HOptimization* optimizations[],
size_t length,
PassObserver* pass_observer) {
RunOptimizations(optimizations1, arraysize(optimizations1), pass_observer);
+ 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;
+ }
+
MaybeRunInliner(graph, driver, stats, dex_compilation_unit, pass_observer, handles);
HOptimization* optimizations2[] = {
RunOptimizations(graph, compiler_driver, compilation_stats_.get(),
dex_compilation_unit, pass_observer, &handles);
+ if (graph->HasTryCatch()) {
+ return nullptr;
+ }
+
AllocateRegisters(graph, codegen, pass_observer);
CodeVectorAllocator allocator;
}
}
- bool can_optimize = CanOptimize(*code_item);
bool can_allocate_registers = RegisterAllocator::CanAllocateRegistersFor(*graph, instruction_set);
// `run_optimizations_` is set explicitly (either through a compiler filter
}
}
- if (can_optimize) {
- return CompileOptimized(graph,
- codegen.get(),
- compiler_driver,
- dex_compilation_unit,
- &pass_observer);
- }
- }
-
- if (shouldOptimize && can_allocate_registers) {
+ return CompileOptimized(graph,
+ codegen.get(),
+ compiler_driver,
+ dex_compilation_unit,
+ &pass_observer);
+ } else if (shouldOptimize && can_allocate_registers) {
LOG(FATAL) << "Could not allocate registers in optimizing compiler";
UNREACHABLE();
} else if (can_use_baseline) {
if (!run_optimizations_) {
MaybeRecordStat(MethodCompilationStat::kNotOptimizedDisabled);
- } else if (!can_optimize) {
- MaybeRecordStat(MethodCompilationStat::kNotOptimizedTryCatch);
} else if (!can_allocate_registers) {
MaybeRecordStat(MethodCompilationStat::kNotOptimizedRegisterAllocator);
}
GrowableArray<HInstruction*>* worklist,
ReferenceTypeInfo::TypeHandle object_class_handle,
ReferenceTypeInfo::TypeHandle class_class_handle,
- ReferenceTypeInfo::TypeHandle string_class_handle)
+ ReferenceTypeInfo::TypeHandle string_class_handle,
+ ReferenceTypeInfo::TypeHandle throwable_class_handle)
: HGraphDelegateVisitor(graph),
handles_(handles),
object_class_handle_(object_class_handle),
class_class_handle_(class_class_handle),
string_class_handle_(string_class_handle),
+ throwable_class_handle_(throwable_class_handle),
worklist_(worklist) {}
void VisitNullConstant(HNullConstant* null_constant) OVERRIDE;
void VisitLoadClass(HLoadClass* load_class) OVERRIDE;
void VisitClinitCheck(HClinitCheck* clinit_check) OVERRIDE;
void VisitLoadString(HLoadString* instr) OVERRIDE;
+ void VisitLoadException(HLoadException* instr) OVERRIDE;
void VisitNewArray(HNewArray* instr) OVERRIDE;
void VisitParameterValue(HParameterValue* instr) OVERRIDE;
void UpdateFieldAccessTypeInfo(HInstruction* instr, const FieldInfo& info);
ReferenceTypeInfo::TypeHandle object_class_handle_;
ReferenceTypeInfo::TypeHandle class_class_handle_;
ReferenceTypeInfo::TypeHandle string_class_handle_;
+ ReferenceTypeInfo::TypeHandle throwable_class_handle_;
GrowableArray<HInstruction*>* worklist_;
static constexpr size_t kDefaultWorklistSize = 8;
object_class_handle_ = handles_->NewHandle(linker->GetClassRoot(ClassLinker::kJavaLangObject));
string_class_handle_ = handles_->NewHandle(linker->GetClassRoot(ClassLinker::kJavaLangString));
class_class_handle_ = handles_->NewHandle(linker->GetClassRoot(ClassLinker::kJavaLangClass));
+ throwable_class_handle_ =
+ handles_->NewHandle(linker->GetClassRoot(ClassLinker::kJavaLangThrowable));
if (kIsDebugBuild) {
ScopedObjectAccess soa(Thread::Current());
DCHECK(ReferenceTypeInfo::IsValidHandle(object_class_handle_));
DCHECK(ReferenceTypeInfo::IsValidHandle(class_class_handle_));
DCHECK(ReferenceTypeInfo::IsValidHandle(string_class_handle_));
+ DCHECK(ReferenceTypeInfo::IsValidHandle(throwable_class_handle_));
}
}
&worklist_,
object_class_handle_,
class_class_handle_,
- string_class_handle_);
+ string_class_handle_,
+ throwable_class_handle_);
// Handle Phis first as there might be instructions in the same block who depend on them.
for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
VisitPhi(it.Current()->AsPhi());
instr->SetReferenceTypeInfo(ReferenceTypeInfo::Create(string_class_handle_, /* is_exact */ true));
}
+void RTPVisitor::VisitLoadException(HLoadException* instr) {
+ DCHECK(instr->GetBlock()->IsCatchBlock());
+ TryCatchInformation* catch_info = instr->GetBlock()->GetTryCatchInformation();
+
+ if (catch_info->IsCatchAllTypeIndex()) {
+ instr->SetReferenceTypeInfo(ReferenceTypeInfo::Create(throwable_class_handle_,
+ /* is_exact */ false));
+ } else {
+ UpdateReferenceTypeInfo(instr,
+ catch_info->GetCatchTypeIndex(),
+ catch_info->GetCatchDexFile(),
+ /* is_exact */ false);
+ }
+}
+
void RTPVisitor::VisitNullCheck(HNullCheck* instr) {
ScopedObjectAccess soa(Thread::Current());
ReferenceTypeInfo parent_rti = instr->InputAt(0)->GetReferenceTypeInfo();
ReferenceTypeInfo::TypeHandle object_class_handle_;
ReferenceTypeInfo::TypeHandle class_class_handle_;
ReferenceTypeInfo::TypeHandle string_class_handle_;
+ ReferenceTypeInfo::TypeHandle throwable_class_handle_;
static constexpr size_t kDefaultWorklistSize = 8;
final class Final {}
+final class FinalException extends Exception {}
+
public class Main {
/// CHECK-START: void Main.testSimpleRemove() instruction_simplifier_after_types (before)
((SubclassA)a[0]).$noinline$g();
}
+ /// CHECK-START: int Main.testLoadExceptionInCatchNonExact(int, int) reference_type_propagation (after)
+ /// CHECK: LoadException klass:java.lang.ArithmeticException can_be_null:false exact:false
+ public int testLoadExceptionInCatchNonExact(int x, int y) {
+ try {
+ return x / y;
+ } catch (ArithmeticException ex) {
+ return ex.hashCode();
+ }
+ }
+
+ /// CHECK-START: int Main.testLoadExceptionInCatchExact(int) reference_type_propagation (after)
+ /// CHECK: LoadException klass:FinalException can_be_null:false exact:true
+ public int testLoadExceptionInCatchExact(int x) {
+ try {
+ if (x == 42) {
+ throw new FinalException();
+ } else {
+ return x;
+ }
+ } catch (FinalException ex) {
+ return ex.hashCode();
+ }
+ }
+
+ /// CHECK-START: int Main.testLoadExceptionInCatchAll(int, int) reference_type_propagation (after)
+ /// CHECK: LoadException klass:java.lang.Throwable can_be_null:false exact:false
+ public int testLoadExceptionInCatchAll(int x, int y) {
+ try {
+ x = x / y;
+ } finally {
+ return x;
+ }
+ }
+
private Generic<SubclassC> genericC = new Generic<SubclassC>();
private Generic<Final> genericFinal = new Generic<Final>();