OSDN Git Service

ART: Move exception clearing into own instruction
authorDavid Brazdil <dbrazdil@google.com>
Tue, 4 Aug 2015 15:22:25 +0000 (16:22 +0100)
committerDavid Brazdil <dbrazdil@google.com>
Tue, 4 Aug 2015 15:39:38 +0000 (16:39 +0100)
Runtime delivers exceptions only to catch blocks which begin with a
MOVE_EXCEPTION instruction (in DEX). In that case, the catch block is
expected to clear the thread-local exception storage after having
read the exception reference.

This patch changes Optimizing to represent MOVE_EXCEPTION with two
instructions - HLoadException and HClearException - instead of one.
If the exception reference is not used, HLoadException can be safely
removed, saving a memory load without breaking the runtime behaviour.

Change-Id: Idad8a714467bf9d9d5fccefbc43c0bd8ae13ddba

compiler/optimizing/builder.cc
compiler/optimizing/code_generator_arm.cc
compiler/optimizing/code_generator_arm64.cc
compiler/optimizing/code_generator_mips64.cc
compiler/optimizing/code_generator_x86.cc
compiler/optimizing/code_generator_x86_64.cc
compiler/optimizing/nodes.h

index 52a3a15..8841498 100644 (file)
@@ -357,9 +357,10 @@ void HGraphBuilder::InsertTryBoundaryBlocks(const DexFile::CodeItem& code_item)
         HInstruction* first_insn = block->GetFirstInstruction();
         if (first_insn->IsLoadException()) {
           // Catch block starts with a LoadException. Split the block after the
-          // StoreLocal that must come after the load.
+          // StoreLocal and ClearException which must come after the load.
           DCHECK(first_insn->GetNext()->IsStoreLocal());
-          block = block->SplitBefore(first_insn->GetNext()->GetNext());
+          DCHECK(first_insn->GetNext()->GetNext()->IsClearException());
+          block = block->SplitBefore(first_insn->GetNext()->GetNext()->GetNext());
         } else {
           // Catch block does not load the exception. Split at the beginning to
           // create an empty catch block.
@@ -2552,6 +2553,7 @@ bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, uint32
     case Instruction::MOVE_EXCEPTION: {
       current_block_->AddInstruction(new (arena_) HLoadException());
       UpdateLocal(instruction.VRegA_11x(), current_block_->GetLastInstruction());
+      current_block_->AddInstruction(new (arena_) HClearException());
       break;
     }
 
index 75b8f06..b0a4ce2 100644 (file)
@@ -4290,6 +4290,10 @@ void InstructionCodeGeneratorARM::VisitLoadString(HLoadString* load) {
   __ Bind(slow_path->GetExitLabel());
 }
 
+static int32_t GetExceptionTlsOffset() {
+  return Thread::ExceptionOffset<kArmWordSize>().Int32Value();
+}
+
 void LocationsBuilderARM::VisitLoadException(HLoadException* load) {
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kNoCall);
@@ -4298,10 +4302,16 @@ void LocationsBuilderARM::VisitLoadException(HLoadException* load) {
 
 void InstructionCodeGeneratorARM::VisitLoadException(HLoadException* load) {
   Register out = load->GetLocations()->Out().AsRegister<Register>();
-  int32_t offset = Thread::ExceptionOffset<kArmWordSize>().Int32Value();
-  __ LoadFromOffset(kLoadWord, out, TR, offset);
+  __ LoadFromOffset(kLoadWord, out, TR, GetExceptionTlsOffset());
+}
+
+void LocationsBuilderARM::VisitClearException(HClearException* clear) {
+  new (GetGraph()->GetArena()) LocationSummary(clear, LocationSummary::kNoCall);
+}
+
+void InstructionCodeGeneratorARM::VisitClearException(HClearException* clear ATTRIBUTE_UNUSED) {
   __ LoadImmediate(IP, 0);
-  __ StoreToOffset(kStoreWord, IP, TR, offset);
+  __ StoreToOffset(kStoreWord, IP, TR, GetExceptionTlsOffset());
 }
 
 void LocationsBuilderARM::VisitThrow(HThrow* instruction) {
index 11de4ee..bbde7e8 100644 (file)
@@ -2496,6 +2496,10 @@ void InstructionCodeGeneratorARM64::VisitLoadClass(HLoadClass* cls) {
   }
 }
 
+static MemOperand GetExceptionTlsAddress() {
+  return MemOperand(tr, Thread::ExceptionOffset<kArm64WordSize>().Int32Value());
+}
+
 void LocationsBuilderARM64::VisitLoadException(HLoadException* load) {
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kNoCall);
@@ -2503,9 +2507,15 @@ void LocationsBuilderARM64::VisitLoadException(HLoadException* load) {
 }
 
 void InstructionCodeGeneratorARM64::VisitLoadException(HLoadException* instruction) {
-  MemOperand exception = MemOperand(tr, Thread::ExceptionOffset<kArm64WordSize>().Int32Value());
-  __ Ldr(OutputRegister(instruction), exception);
-  __ Str(wzr, exception);
+  __ Ldr(OutputRegister(instruction), GetExceptionTlsAddress());
+}
+
+void LocationsBuilderARM64::VisitClearException(HClearException* clear) {
+  new (GetGraph()->GetArena()) LocationSummary(clear, LocationSummary::kNoCall);
+}
+
+void InstructionCodeGeneratorARM64::VisitClearException(HClearException* clear ATTRIBUTE_UNUSED) {
+  __ Str(wzr, GetExceptionTlsAddress());
 }
 
 void LocationsBuilderARM64::VisitLoadLocal(HLoadLocal* load) {
index e7d2ec6..a5bad65 100644 (file)
@@ -2544,6 +2544,10 @@ void InstructionCodeGeneratorMIPS64::VisitLoadClass(HLoadClass* cls) {
   }
 }
 
+static int32_t GetExceptionTlsOffset() {
+  return Thread::ExceptionOffset<kMips64WordSize>().Int32Value();
+}
+
 void LocationsBuilderMIPS64::VisitLoadException(HLoadException* load) {
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kNoCall);
@@ -2552,8 +2556,15 @@ void LocationsBuilderMIPS64::VisitLoadException(HLoadException* load) {
 
 void InstructionCodeGeneratorMIPS64::VisitLoadException(HLoadException* load) {
   GpuRegister out = load->GetLocations()->Out().AsRegister<GpuRegister>();
-  __ LoadFromOffset(kLoadUnsignedWord, out, TR, Thread::ExceptionOffset<kMips64WordSize>().Int32Value());
-  __ StoreToOffset(kStoreWord, ZERO, TR, Thread::ExceptionOffset<kMips64WordSize>().Int32Value());
+  __ LoadFromOffset(kLoadUnsignedWord, out, TR, GetExceptionTlsOffset());
+}
+
+void LocationsBuilderMIPS64::VisitClearException(HClearException* clear) {
+  new (GetGraph()->GetArena()) LocationSummary(clear, LocationSummary::kNoCall);
+}
+
+void InstructionCodeGeneratorMIPS64::VisitClearException(HClearException* clear ATTRIBUTE_UNUSED) {
+  __ StoreToOffset(kStoreWord, ZERO, TR, GetExceptionTlsOffset());
 }
 
 void LocationsBuilderMIPS64::VisitLoadLocal(HLoadLocal* load) {
index 0569565..fdef06b 100644 (file)
@@ -4693,6 +4693,10 @@ void InstructionCodeGeneratorX86::VisitLoadString(HLoadString* load) {
   __ Bind(slow_path->GetExitLabel());
 }
 
+static Address GetExceptionTlsAddress() {
+  return Address::Absolute(Thread::ExceptionOffset<kX86WordSize>().Int32Value());
+}
+
 void LocationsBuilderX86::VisitLoadException(HLoadException* load) {
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kNoCall);
@@ -4700,9 +4704,15 @@ void LocationsBuilderX86::VisitLoadException(HLoadException* load) {
 }
 
 void InstructionCodeGeneratorX86::VisitLoadException(HLoadException* load) {
-  Address address = Address::Absolute(Thread::ExceptionOffset<kX86WordSize>().Int32Value());
-  __ fs()->movl(load->GetLocations()->Out().AsRegister<Register>(), address);
-  __ fs()->movl(address, Immediate(0));
+  __ fs()->movl(load->GetLocations()->Out().AsRegister<Register>(), GetExceptionTlsAddress());
+}
+
+void LocationsBuilderX86::VisitClearException(HClearException* clear) {
+  new (GetGraph()->GetArena()) LocationSummary(clear, LocationSummary::kNoCall);
+}
+
+void InstructionCodeGeneratorX86::VisitClearException(HClearException* clear ATTRIBUTE_UNUSED) {
+  __ fs()->movl(GetExceptionTlsAddress(), Immediate(0));
 }
 
 void LocationsBuilderX86::VisitThrow(HThrow* instruction) {
index 287737b..4fe93f9 100644 (file)
@@ -4527,6 +4527,10 @@ void InstructionCodeGeneratorX86_64::VisitLoadString(HLoadString* load) {
   __ Bind(slow_path->GetExitLabel());
 }
 
+static Address GetExceptionTlsAddress() {
+  return Address::Absolute(Thread::ExceptionOffset<kX86_64WordSize>().Int32Value(), true);
+}
+
 void LocationsBuilderX86_64::VisitLoadException(HLoadException* load) {
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kNoCall);
@@ -4534,10 +4538,15 @@ void LocationsBuilderX86_64::VisitLoadException(HLoadException* load) {
 }
 
 void InstructionCodeGeneratorX86_64::VisitLoadException(HLoadException* load) {
-  Address address = Address::Absolute(
-      Thread::ExceptionOffset<kX86_64WordSize>().Int32Value(), true);
-  __ gs()->movl(load->GetLocations()->Out().AsRegister<CpuRegister>(), address);
-  __ gs()->movl(address, Immediate(0));
+  __ gs()->movl(load->GetLocations()->Out().AsRegister<CpuRegister>(), GetExceptionTlsAddress());
+}
+
+void LocationsBuilderX86_64::VisitClearException(HClearException* clear) {
+  new (GetGraph()->GetArena()) LocationSummary(clear, LocationSummary::kNoCall);
+}
+
+void InstructionCodeGeneratorX86_64::VisitClearException(HClearException* clear ATTRIBUTE_UNUSED) {
+  __ gs()->movl(GetExceptionTlsAddress(), Immediate(0));
 }
 
 void LocationsBuilderX86_64::VisitThrow(HThrow* instruction) {
index 9b8521d..638ac95 100644 (file)
@@ -961,6 +961,7 @@ class HLoopInformationOutwardIterator : public ValueObject {
   M(BoundsCheck, Instruction)                                           \
   M(BoundType, Instruction)                                             \
   M(CheckCast, Instruction)                                             \
+  M(ClearException, Instruction)                                        \
   M(ClinitCheck, Instruction)                                           \
   M(Compare, BinaryOperation)                                           \
   M(Condition, BinaryOperation)                                         \
@@ -4142,6 +4143,18 @@ class HLoadException : public HExpression<0> {
   DISALLOW_COPY_AND_ASSIGN(HLoadException);
 };
 
+// Implicit part of move-exception which clears thread-local exception storage.
+// Must not be removed because the runtime expects the TLS to get cleared.
+class HClearException : public HTemplateInstruction<0> {
+ public:
+  HClearException() : HTemplateInstruction(SideEffects::AllWrites()) {}
+
+  DECLARE_INSTRUCTION(ClearException);
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(HClearException);
+};
+
 class HThrow : public HTemplateInstruction<1> {
  public:
   HThrow(HInstruction* exception, uint32_t dex_pc)