Support for inlining methods that call/throw.

Mostly fixes here and there to make it working.

Change-Id: I1b535e895105d78b65634636d675b818551f783e
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index 3144c5c..005d50e 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -143,6 +143,7 @@
         dex_file_(dex_file),
         method_idx_(method_idx),
         invoke_type_(invoke_type),
+        in_ssa_form_(false),
         should_generate_constructor_barrier_(should_generate_constructor_barrier),
         cached_null_constant_(nullptr),
         cached_int_constants_(std::less<int32_t>(), arena->Adapter()),
@@ -174,6 +175,7 @@
     // users remaining when being visited.
     if (!AnalyzeNaturalLoops()) return false;
     TransformToSsa();
+    in_ssa_form_ = true;
     return true;
   }
 
@@ -216,11 +218,16 @@
     maximum_number_of_out_vregs_ = new_value;
   }
 
+  void UpdateMaximumNumberOfOutVRegs(uint16_t other_value) {
+    maximum_number_of_out_vregs_ = std::max(maximum_number_of_out_vregs_, other_value);
+  }
+
   void UpdateTemporariesVRegSlots(size_t slots) {
     temporaries_vreg_slots_ = std::max(slots, temporaries_vreg_slots_);
   }
 
   size_t GetTemporariesVRegSlots() const {
+    DCHECK(!in_ssa_form_);
     return temporaries_vreg_slots_;
   }
 
@@ -229,6 +236,7 @@
   }
 
   uint16_t GetNumberOfVRegs() const {
+    DCHECK(!in_ssa_form_);
     return number_of_vregs_;
   }
 
@@ -237,6 +245,7 @@
   }
 
   uint16_t GetNumberOfLocalVRegs() const {
+    DCHECK(!in_ssa_form_);
     return number_of_vregs_ - number_of_in_vregs_;
   }
 
@@ -381,6 +390,11 @@
   // If inlined, this encodes how the callee is being invoked.
   const InvokeType invoke_type_;
 
+  // Whether the graph has been transformed to SSA form. Only used
+  // in debug mode to ensure we are not using properties only valid
+  // for non-SSA form (like the number of temporaries).
+  bool in_ssa_form_;
+
   const bool should_generate_constructor_barrier_;
 
   // Cached constants.
@@ -1121,14 +1135,16 @@
                const DexFile& dex_file,
                uint32_t method_idx,
                uint32_t dex_pc,
-               InvokeType invoke_type)
+               InvokeType invoke_type,
+               HInstruction* holder)
      : vregs_(arena, number_of_vregs),
        locations_(arena, number_of_vregs),
        parent_(nullptr),
        dex_file_(dex_file),
        method_idx_(method_idx),
        dex_pc_(dex_pc),
-       invoke_type_(invoke_type) {
+       invoke_type_(invoke_type),
+       holder_(holder) {
     vregs_.SetSize(number_of_vregs);
     for (size_t i = 0; i < number_of_vregs; i++) {
       vregs_.Put(i, HUserRecord<HEnvironment*>());
@@ -1140,19 +1156,24 @@
     }
   }
 
-  HEnvironment(ArenaAllocator* arena, const HEnvironment& to_copy)
+  HEnvironment(ArenaAllocator* arena, const HEnvironment& to_copy, HInstruction* holder)
       : HEnvironment(arena,
                      to_copy.Size(),
                      to_copy.GetDexFile(),
                      to_copy.GetMethodIdx(),
                      to_copy.GetDexPc(),
-                     to_copy.GetInvokeType()) {}
+                     to_copy.GetInvokeType(),
+                     holder) {}
 
   void SetAndCopyParentChain(ArenaAllocator* allocator, HEnvironment* parent) {
-    parent_ = new (allocator) HEnvironment(allocator, *parent);
-    parent_->CopyFrom(parent);
-    if (parent->GetParent() != nullptr) {
-      parent_->SetAndCopyParentChain(allocator, parent->GetParent());
+    if (parent_ != nullptr) {
+      parent_->SetAndCopyParentChain(allocator, parent);
+    } else {
+      parent_ = new (allocator) HEnvironment(allocator, *parent, holder_);
+      parent_->CopyFrom(parent);
+      if (parent->GetParent() != nullptr) {
+        parent_->SetAndCopyParentChain(allocator, parent->GetParent());
+      }
     }
   }
 
@@ -1202,6 +1223,10 @@
     return dex_file_;
   }
 
+  HInstruction* GetHolder() const {
+    return holder_;
+  }
+
  private:
   // Record instructions' use entries of this environment for constant-time removal.
   // It should only be called by HInstruction when a new environment use is added.
@@ -1219,6 +1244,10 @@
   const uint32_t dex_pc_;
   const InvokeType invoke_type_;
 
+  // The instruction that holds this environment. Only used in debug mode
+  // to ensure the graph is consistent.
+  HInstruction* const holder_;
+
   friend class HInstruction;
 
   DISALLOW_COPY_AND_ASSIGN(HEnvironment);
@@ -1425,13 +1454,18 @@
   HEnvironment* GetEnvironment() const { return environment_; }
   // Set the `environment_` field. Raw because this method does not
   // update the uses lists.
-  void SetRawEnvironment(HEnvironment* environment) { environment_ = environment; }
+  void SetRawEnvironment(HEnvironment* environment) {
+    DCHECK(environment_ == nullptr);
+    DCHECK_EQ(environment->GetHolder(), this);
+    environment_ = environment;
+  }
 
   // Set the environment of this instruction, copying it from `environment`. While
   // copying, the uses lists are being updated.
   void CopyEnvironmentFrom(HEnvironment* environment) {
+    DCHECK(environment_ == nullptr);
     ArenaAllocator* allocator = GetBlock()->GetGraph()->GetArena();
-    environment_ = new (allocator) HEnvironment(allocator, *environment);
+    environment_ = new (allocator) HEnvironment(allocator, *environment, this);
     environment_->CopyFrom(environment);
     if (environment->GetParent() != nullptr) {
       environment_->SetAndCopyParentChain(allocator, environment->GetParent());
@@ -1440,8 +1474,9 @@
 
   void CopyEnvironmentFromWithLoopPhiAdjustment(HEnvironment* environment,
                                                 HBasicBlock* block) {
+    DCHECK(environment_ == nullptr);
     ArenaAllocator* allocator = GetBlock()->GetGraph()->GetArena();
-    environment_ = new (allocator) HEnvironment(allocator, *environment);
+    environment_ = new (allocator) HEnvironment(allocator, *environment, this);
     environment_->CopyFromWithLoopPhiAdjustment(environment, block);
     if (environment->GetParent() != nullptr) {
       environment_->SetAndCopyParentChain(allocator, environment->GetParent());
@@ -2420,6 +2455,12 @@
     intrinsic_ = intrinsic;
   }
 
+  bool IsInlined() const {
+    return GetEnvironment()->GetParent() != nullptr;
+  }
+
+  bool CanThrow() const OVERRIDE { return true; }
+
   DECLARE_INSTRUCTION(Invoke);
 
  protected: