Merge "ART: Add missing GetInterfaceMethodIfProxy"
diff --git a/compiler/optimizing/builder.cc b/compiler/optimizing/builder.cc
index 1650fd1..7a3aa58 100644
--- a/compiler/optimizing/builder.cc
+++ b/compiler/optimizing/builder.cc
@@ -46,7 +46,7 @@
   explicit Temporaries(HGraph* graph) : graph_(graph), index_(0) {}
 
   void Add(HInstruction* instruction) {
-    HInstruction* temp = new (graph_->GetArena()) HTemporary(index_);
+    HInstruction* temp = new (graph_->GetArena()) HTemporary(index_, instruction->GetDexPc());
     instruction->GetBlock()->AddInstruction(temp);
 
     DCHECK(temp->GetPrevious() == instruction);
@@ -161,23 +161,25 @@
 
   if (!dex_compilation_unit_->IsStatic()) {
     // Add the implicit 'this' argument, not expressed in the signature.
-    HParameterValue* parameter =
-        new (arena_) HParameterValue(parameter_index++, Primitive::kPrimNot, true);
+    HParameterValue* parameter = new (arena_) HParameterValue(parameter_index++,
+                                                              Primitive::kPrimNot,
+                                                              true);
     entry_block_->AddInstruction(parameter);
     HLocal* local = GetLocalAt(locals_index++);
-    entry_block_->AddInstruction(new (arena_) HStoreLocal(local, parameter));
+    entry_block_->AddInstruction(new (arena_) HStoreLocal(local, parameter, local->GetDexPc()));
     number_of_parameters--;
   }
 
   uint32_t pos = 1;
   for (int i = 0; i < number_of_parameters; i++) {
-    HParameterValue* parameter =
-        new (arena_) HParameterValue(parameter_index++, Primitive::GetType(shorty[pos++]));
+    HParameterValue* parameter = new (arena_) HParameterValue(parameter_index++,
+                                                              Primitive::GetType(shorty[pos++]),
+                                                              false);
     entry_block_->AddInstruction(parameter);
     HLocal* local = GetLocalAt(locals_index++);
     // Store the parameter value in the local that the dex code will use
     // to reference that parameter.
-    entry_block_->AddInstruction(new (arena_) HStoreLocal(local, parameter));
+    entry_block_->AddInstruction(new (arena_) HStoreLocal(local, parameter, local->GetDexPc()));
     bool is_wide = (parameter->GetType() == Primitive::kPrimLong)
         || (parameter->GetType() == Primitive::kPrimDouble);
     if (is_wide) {
@@ -196,11 +198,11 @@
   DCHECK(branch_target != nullptr);
   DCHECK(fallthrough_target != nullptr);
   PotentiallyAddSuspendCheck(branch_target, dex_pc);
-  HInstruction* first = LoadLocal(instruction.VRegA(), Primitive::kPrimInt);
-  HInstruction* second = LoadLocal(instruction.VRegB(), Primitive::kPrimInt);
-  T* comparison = new (arena_) T(first, second);
+  HInstruction* first = LoadLocal(instruction.VRegA(), Primitive::kPrimInt, dex_pc);
+  HInstruction* second = LoadLocal(instruction.VRegB(), Primitive::kPrimInt, dex_pc);
+  T* comparison = new (arena_) T(first, second, dex_pc);
   current_block_->AddInstruction(comparison);
-  HInstruction* ifinst = new (arena_) HIf(comparison);
+  HInstruction* ifinst = new (arena_) HIf(comparison, dex_pc);
   current_block_->AddInstruction(ifinst);
   current_block_->AddSuccessor(branch_target);
   current_block_->AddSuccessor(fallthrough_target);
@@ -215,10 +217,10 @@
   DCHECK(branch_target != nullptr);
   DCHECK(fallthrough_target != nullptr);
   PotentiallyAddSuspendCheck(branch_target, dex_pc);
-  HInstruction* value = LoadLocal(instruction.VRegA(), Primitive::kPrimInt);
-  T* comparison = new (arena_) T(value, graph_->GetIntConstant(0));
+  HInstruction* value = LoadLocal(instruction.VRegA(), Primitive::kPrimInt, dex_pc);
+  T* comparison = new (arena_) T(value, graph_->GetIntConstant(0, dex_pc), dex_pc);
   current_block_->AddInstruction(comparison);
-  HInstruction* ifinst = new (arena_) HIf(comparison);
+  HInstruction* ifinst = new (arena_) HIf(comparison, dex_pc);
   current_block_->AddInstruction(ifinst);
   current_block_->AddSuccessor(branch_target);
   current_block_->AddSuccessor(fallthrough_target);
@@ -320,7 +322,7 @@
                                          const DexFile::CodeItem& code_item,
                                          const DexFile::TryItem& try_item) {
   // Split the edge with a single TryBoundary instruction.
-  HTryBoundary* try_boundary = new (arena_) HTryBoundary(kind);
+  HTryBoundary* try_boundary = new (arena_) HTryBoundary(kind, successor->GetDexPc());
   HBasicBlock* try_entry_block = graph_->SplitEdge(predecessor, successor);
   try_entry_block->AddInstruction(try_boundary);
 
@@ -538,7 +540,7 @@
     // Branching instructions clear current_block, so we know
     // the last instruction of the current block is not a branching
     // instruction. We add an unconditional goto to the found block.
-    current_block_->AddInstruction(new (arena_) HGoto());
+    current_block_->AddInstruction(new (arena_) HGoto(dex_pc));
     current_block_->AddSuccessor(block);
   }
   graph_->AddBlock(block);
@@ -634,104 +636,92 @@
 }
 
 template<typename T>
-void HGraphBuilder::Unop_12x(const Instruction& instruction, Primitive::Type type) {
-  HInstruction* first = LoadLocal(instruction.VRegB(), type);
-  current_block_->AddInstruction(new (arena_) T(type, first));
-  UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction());
+void HGraphBuilder::Unop_12x(const Instruction& instruction,
+                             Primitive::Type type,
+                             uint32_t dex_pc) {
+  HInstruction* first = LoadLocal(instruction.VRegB(), type, dex_pc);
+  current_block_->AddInstruction(new (arena_) T(type, first, dex_pc));
+  UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction(), dex_pc);
 }
 
 void HGraphBuilder::Conversion_12x(const Instruction& instruction,
                                    Primitive::Type input_type,
                                    Primitive::Type result_type,
                                    uint32_t dex_pc) {
-  HInstruction* first = LoadLocal(instruction.VRegB(), input_type);
+  HInstruction* first = LoadLocal(instruction.VRegB(), input_type, dex_pc);
   current_block_->AddInstruction(new (arena_) HTypeConversion(result_type, first, dex_pc));
-  UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction());
-}
-
-template<typename T>
-void HGraphBuilder::Binop_23x(const Instruction& instruction, Primitive::Type type) {
-  HInstruction* first = LoadLocal(instruction.VRegB(), type);
-  HInstruction* second = LoadLocal(instruction.VRegC(), type);
-  current_block_->AddInstruction(new (arena_) T(type, first, second));
-  UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction());
+  UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction(), dex_pc);
 }
 
 template<typename T>
 void HGraphBuilder::Binop_23x(const Instruction& instruction,
                               Primitive::Type type,
                               uint32_t dex_pc) {
-  HInstruction* first = LoadLocal(instruction.VRegB(), type);
-  HInstruction* second = LoadLocal(instruction.VRegC(), type);
+  HInstruction* first = LoadLocal(instruction.VRegB(), type, dex_pc);
+  HInstruction* second = LoadLocal(instruction.VRegC(), type, dex_pc);
   current_block_->AddInstruction(new (arena_) T(type, first, second, dex_pc));
-  UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction());
+  UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction(), dex_pc);
 }
 
 template<typename T>
 void HGraphBuilder::Binop_23x_shift(const Instruction& instruction,
-                                    Primitive::Type type) {
-  HInstruction* first = LoadLocal(instruction.VRegB(), type);
-  HInstruction* second = LoadLocal(instruction.VRegC(), Primitive::kPrimInt);
-  current_block_->AddInstruction(new (arena_) T(type, first, second));
-  UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction());
+                                    Primitive::Type type,
+                                    uint32_t dex_pc) {
+  HInstruction* first = LoadLocal(instruction.VRegB(), type, dex_pc);
+  HInstruction* second = LoadLocal(instruction.VRegC(), Primitive::kPrimInt, dex_pc);
+  current_block_->AddInstruction(new (arena_) T(type, first, second, dex_pc));
+  UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction(), dex_pc);
 }
 
 void HGraphBuilder::Binop_23x_cmp(const Instruction& instruction,
                                   Primitive::Type type,
                                   ComparisonBias bias,
                                   uint32_t dex_pc) {
-  HInstruction* first = LoadLocal(instruction.VRegB(), type);
-  HInstruction* second = LoadLocal(instruction.VRegC(), type);
+  HInstruction* first = LoadLocal(instruction.VRegB(), type, dex_pc);
+  HInstruction* second = LoadLocal(instruction.VRegC(), type, dex_pc);
   current_block_->AddInstruction(new (arena_) HCompare(type, first, second, bias, dex_pc));
-  UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction());
+  UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction(), dex_pc);
 }
 
 template<typename T>
-void HGraphBuilder::Binop_12x(const Instruction& instruction, Primitive::Type type) {
-  HInstruction* first = LoadLocal(instruction.VRegA(), type);
-  HInstruction* second = LoadLocal(instruction.VRegB(), type);
-  current_block_->AddInstruction(new (arena_) T(type, first, second));
-  UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction());
-}
-
-template<typename T>
-void HGraphBuilder::Binop_12x_shift(const Instruction& instruction, Primitive::Type type) {
-  HInstruction* first = LoadLocal(instruction.VRegA(), type);
-  HInstruction* second = LoadLocal(instruction.VRegB(), Primitive::kPrimInt);
-  current_block_->AddInstruction(new (arena_) T(type, first, second));
-  UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction());
+void HGraphBuilder::Binop_12x_shift(const Instruction& instruction, Primitive::Type type,
+                                    uint32_t dex_pc) {
+  HInstruction* first = LoadLocal(instruction.VRegA(), type, dex_pc);
+  HInstruction* second = LoadLocal(instruction.VRegB(), Primitive::kPrimInt, dex_pc);
+  current_block_->AddInstruction(new (arena_) T(type, first, second, dex_pc));
+  UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction(), dex_pc);
 }
 
 template<typename T>
 void HGraphBuilder::Binop_12x(const Instruction& instruction,
                               Primitive::Type type,
                               uint32_t dex_pc) {
-  HInstruction* first = LoadLocal(instruction.VRegA(), type);
-  HInstruction* second = LoadLocal(instruction.VRegB(), type);
+  HInstruction* first = LoadLocal(instruction.VRegA(), type, dex_pc);
+  HInstruction* second = LoadLocal(instruction.VRegB(), type, dex_pc);
   current_block_->AddInstruction(new (arena_) T(type, first, second, dex_pc));
-  UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction());
+  UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction(), dex_pc);
 }
 
 template<typename T>
-void HGraphBuilder::Binop_22s(const Instruction& instruction, bool reverse) {
-  HInstruction* first = LoadLocal(instruction.VRegB(), Primitive::kPrimInt);
-  HInstruction* second = graph_->GetIntConstant(instruction.VRegC_22s());
+void HGraphBuilder::Binop_22s(const Instruction& instruction, bool reverse, uint32_t dex_pc) {
+  HInstruction* first = LoadLocal(instruction.VRegB(), Primitive::kPrimInt, dex_pc);
+  HInstruction* second = graph_->GetIntConstant(instruction.VRegC_22s(), dex_pc);
   if (reverse) {
     std::swap(first, second);
   }
-  current_block_->AddInstruction(new (arena_) T(Primitive::kPrimInt, first, second));
-  UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction());
+  current_block_->AddInstruction(new (arena_) T(Primitive::kPrimInt, first, second, dex_pc));
+  UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction(), dex_pc);
 }
 
 template<typename T>
-void HGraphBuilder::Binop_22b(const Instruction& instruction, bool reverse) {
-  HInstruction* first = LoadLocal(instruction.VRegB(), Primitive::kPrimInt);
-  HInstruction* second = graph_->GetIntConstant(instruction.VRegC_22b());
+void HGraphBuilder::Binop_22b(const Instruction& instruction, bool reverse, uint32_t dex_pc) {
+  HInstruction* first = LoadLocal(instruction.VRegB(), Primitive::kPrimInt, dex_pc);
+  HInstruction* second = graph_->GetIntConstant(instruction.VRegC_22b(), dex_pc);
   if (reverse) {
     std::swap(first, second);
   }
-  current_block_->AddInstruction(new (arena_) T(Primitive::kPrimInt, first, second));
-  UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction());
+  current_block_->AddInstruction(new (arena_) T(Primitive::kPrimInt, first, second, dex_pc));
+  UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction(), dex_pc);
 }
 
 static bool RequiresConstructorBarrier(const DexCompilationUnit* cu, const CompilerDriver& driver) {
@@ -740,7 +730,9 @@
       && driver.RequiresConstructorBarrier(self, cu->GetDexFile(), cu->GetClassDefIndex());
 }
 
-void HGraphBuilder::BuildReturn(const Instruction& instruction, Primitive::Type type) {
+void HGraphBuilder::BuildReturn(const Instruction& instruction,
+                                Primitive::Type type,
+                                uint32_t dex_pc) {
   if (type == Primitive::kPrimVoid) {
     if (graph_->ShouldGenerateConstructorBarrier()) {
       // The compilation unit is null during testing.
@@ -748,12 +740,12 @@
         DCHECK(RequiresConstructorBarrier(dex_compilation_unit_, *compiler_driver_))
           << "Inconsistent use of ShouldGenerateConstructorBarrier. Should not generate a barrier.";
       }
-      current_block_->AddInstruction(new (arena_) HMemoryBarrier(kStoreStore));
+      current_block_->AddInstruction(new (arena_) HMemoryBarrier(kStoreStore, dex_pc));
     }
-    current_block_->AddInstruction(new (arena_) HReturnVoid());
+    current_block_->AddInstruction(new (arena_) HReturnVoid(dex_pc));
   } else {
-    HInstruction* value = LoadLocal(instruction.VRegA(), type);
-    current_block_->AddInstruction(new (arena_) HReturn(value));
+    HInstruction* value = LoadLocal(instruction.VRegA(), type, dex_pc);
+    current_block_->AddInstruction(new (arena_) HReturn(value, dex_pc));
   }
   current_block_->AddSuccessor(exit_block_);
   current_block_ = nullptr;
@@ -1050,6 +1042,7 @@
   size_t start_index = 0;
   size_t argument_index = 0;
   uint32_t descriptor_index = 1;  // Skip the return type.
+  uint32_t dex_pc = invoke->GetDexPc();
 
   bool is_instance_call = invoke->GetOriginalInvokeType() != InvokeType::kStatic;
   bool is_string_init = invoke->IsInvokeStaticOrDirect()
@@ -1060,7 +1053,7 @@
     argument_index = 0;
   } else if (is_instance_call) {
     Temporaries temps(graph_);
-    HInstruction* arg = LoadLocal(is_range ? register_index : args[0], Primitive::kPrimNot);
+    HInstruction* arg = LoadLocal(is_range ? register_index : args[0], Primitive::kPrimNot, dex_pc);
     HNullCheck* null_check = new (arena_) HNullCheck(arg, invoke->GetDexPc());
     current_block_->AddInstruction(null_check);
     temps.Add(null_check);
@@ -1089,7 +1082,7 @@
       MaybeRecordStat(MethodCompilationStat::kNotCompiledMalformedOpcode);
       return false;
     }
-    HInstruction* arg = LoadLocal(is_range ? register_index + i : args[i], type);
+    HInstruction* arg = LoadLocal(is_range ? register_index + i : args[i], type, dex_pc);
     invoke->SetArgumentAt(argument_index, arg);
     if (is_wide) {
       i++;
@@ -1122,7 +1115,7 @@
   // Add move-result for StringFactory method.
   if (is_string_init) {
     uint32_t orig_this_reg = is_range ? register_index : args[0];
-    HInstruction* fake_string = LoadLocal(orig_this_reg, Primitive::kPrimNot);
+    HInstruction* fake_string = LoadLocal(orig_this_reg, Primitive::kPrimNot, dex_pc);
     invoke->SetArgumentAt(argument_index, fake_string);
     current_block_->AddInstruction(invoke);
     PotentiallySimplifyFakeString(orig_this_reg, invoke->GetDexPc(), invoke);
@@ -1148,15 +1141,15 @@
   const VerifiedMethod* verified_method =
       compiler_driver_->GetVerifiedMethod(dex_file_, dex_compilation_unit_->GetDexMethodIndex());
   if (verified_method != nullptr) {
-    UpdateLocal(original_dex_register, actual_string);
+    UpdateLocal(original_dex_register, actual_string, dex_pc);
     const SafeMap<uint32_t, std::set<uint32_t>>& string_init_map =
         verified_method->GetStringInitPcRegMap();
     auto map_it = string_init_map.find(dex_pc);
     if (map_it != string_init_map.end()) {
       std::set<uint32_t> reg_set = map_it->second;
       for (auto set_it = reg_set.begin(); set_it != reg_set.end(); ++set_it) {
-        HInstruction* load_local = LoadLocal(original_dex_register, Primitive::kPrimNot);
-        UpdateLocal(*set_it, load_local);
+        HInstruction* load_local = LoadLocal(original_dex_register, Primitive::kPrimNot, dex_pc);
+        UpdateLocal(*set_it, load_local, dex_pc);
       }
     }
   } else {
@@ -1190,14 +1183,14 @@
 
   Primitive::Type field_type = resolved_field->GetTypeAsPrimitiveType();
 
-  HInstruction* object = LoadLocal(obj_reg, Primitive::kPrimNot);
+  HInstruction* object = LoadLocal(obj_reg, Primitive::kPrimNot, dex_pc);
   current_block_->AddInstruction(new (arena_) HNullCheck(object, dex_pc));
   if (is_put) {
     Temporaries temps(graph_);
     HInstruction* null_check = current_block_->GetLastInstruction();
     // We need one temporary for the null check.
     temps.Add(null_check);
-    HInstruction* value = LoadLocal(source_or_dest_reg, field_type);
+    HInstruction* value = LoadLocal(source_or_dest_reg, field_type, dex_pc);
     current_block_->AddInstruction(new (arena_) HInstanceFieldSet(
         null_check,
         value,
@@ -1206,7 +1199,8 @@
         resolved_field->IsVolatile(),
         field_index,
         *dex_file_,
-        dex_compilation_unit_->GetDexCache()));
+        dex_compilation_unit_->GetDexCache(),
+        dex_pc));
   } else {
     current_block_->AddInstruction(new (arena_) HInstanceFieldGet(
         current_block_->GetLastInstruction(),
@@ -1215,9 +1209,10 @@
         resolved_field->IsVolatile(),
         field_index,
         *dex_file_,
-        dex_compilation_unit_->GetDexCache()));
+        dex_compilation_unit_->GetDexCache(),
+        dex_pc));
 
-    UpdateLocal(source_or_dest_reg, current_block_->GetLastInstruction());
+    UpdateLocal(source_or_dest_reg, current_block_->GetLastInstruction(), dex_pc);
   }
   return true;
 }
@@ -1328,7 +1323,7 @@
     // We need to keep the class alive before loading the value.
     Temporaries temps(graph_);
     temps.Add(cls);
-    HInstruction* value = LoadLocal(source_or_dest_reg, field_type);
+    HInstruction* value = LoadLocal(source_or_dest_reg, field_type, dex_pc);
     DCHECK_EQ(value->GetType(), field_type);
     current_block_->AddInstruction(new (arena_) HStaticFieldSet(cls,
                                                                 value,
@@ -1337,7 +1332,8 @@
                                                                 resolved_field->IsVolatile(),
                                                                 field_index,
                                                                 *dex_file_,
-                                                                dex_cache_));
+                                                                dex_cache_,
+                                                                dex_pc));
   } else {
     current_block_->AddInstruction(new (arena_) HStaticFieldGet(cls,
                                                                 field_type,
@@ -1345,8 +1341,9 @@
                                                                 resolved_field->IsVolatile(),
                                                                 field_index,
                                                                 *dex_file_,
-                                                                dex_cache_));
-    UpdateLocal(source_or_dest_reg, current_block_->GetLastInstruction());
+                                                                dex_cache_,
+                                                                dex_pc));
+    UpdateLocal(source_or_dest_reg, current_block_->GetLastInstruction(), dex_pc);
   }
   return true;
 }
@@ -1360,16 +1357,16 @@
                                        bool isDiv) {
   DCHECK(type == Primitive::kPrimInt || type == Primitive::kPrimLong);
 
-  HInstruction* first = LoadLocal(first_vreg, type);
+  HInstruction* first = LoadLocal(first_vreg, type, dex_pc);
   HInstruction* second = nullptr;
   if (second_is_constant) {
     if (type == Primitive::kPrimInt) {
-      second = graph_->GetIntConstant(second_vreg_or_constant);
+      second = graph_->GetIntConstant(second_vreg_or_constant, dex_pc);
     } else {
-      second = graph_->GetLongConstant(second_vreg_or_constant);
+      second = graph_->GetLongConstant(second_vreg_or_constant, dex_pc);
     }
   } else {
-    second = LoadLocal(second_vreg_or_constant, type);
+    second = LoadLocal(second_vreg_or_constant, type, dex_pc);
   }
 
   if (!second_is_constant
@@ -1386,7 +1383,7 @@
   } else {
     current_block_->AddInstruction(new (arena_) HRem(type, first, second, dex_pc));
   }
-  UpdateLocal(out_vreg, current_block_->GetLastInstruction());
+  UpdateLocal(out_vreg, current_block_->GetLastInstruction(), dex_pc);
 }
 
 void HGraphBuilder::BuildArrayAccess(const Instruction& instruction,
@@ -1400,26 +1397,26 @@
   // We need one temporary for the null check, one for the index, and one for the length.
   Temporaries temps(graph_);
 
-  HInstruction* object = LoadLocal(array_reg, Primitive::kPrimNot);
+  HInstruction* object = LoadLocal(array_reg, Primitive::kPrimNot, dex_pc);
   object = new (arena_) HNullCheck(object, dex_pc);
   current_block_->AddInstruction(object);
   temps.Add(object);
 
-  HInstruction* length = new (arena_) HArrayLength(object);
+  HInstruction* length = new (arena_) HArrayLength(object, dex_pc);
   current_block_->AddInstruction(length);
   temps.Add(length);
-  HInstruction* index = LoadLocal(index_reg, Primitive::kPrimInt);
+  HInstruction* index = LoadLocal(index_reg, Primitive::kPrimInt, dex_pc);
   index = new (arena_) HBoundsCheck(index, length, dex_pc);
   current_block_->AddInstruction(index);
   temps.Add(index);
   if (is_put) {
-    HInstruction* value = LoadLocal(source_or_dest_reg, anticipated_type);
+    HInstruction* value = LoadLocal(source_or_dest_reg, anticipated_type, dex_pc);
     // TODO: Insert a type check node if the type is Object.
     current_block_->AddInstruction(new (arena_) HArraySet(
         object, index, value, anticipated_type, dex_pc));
   } else {
-    current_block_->AddInstruction(new (arena_) HArrayGet(object, index, anticipated_type));
-    UpdateLocal(source_or_dest_reg, current_block_->GetLastInstruction());
+    current_block_->AddInstruction(new (arena_) HArrayGet(object, index, anticipated_type, dex_pc));
+    UpdateLocal(source_or_dest_reg, current_block_->GetLastInstruction(), dex_pc);
   }
   graph_->SetHasBoundsChecks(true);
 }
@@ -1430,7 +1427,7 @@
                                         bool is_range,
                                         uint32_t* args,
                                         uint32_t register_index) {
-  HInstruction* length = graph_->GetIntConstant(number_of_vreg_arguments);
+  HInstruction* length = graph_->GetIntConstant(number_of_vreg_arguments, dex_pc);
   QuickEntrypointEnum entrypoint = NeedsAccessCheck(type_index)
       ? kQuickAllocArrayWithAccessCheck
       : kQuickAllocArray;
@@ -1454,8 +1451,8 @@
   Temporaries temps(graph_);
   temps.Add(object);
   for (size_t i = 0; i < number_of_vreg_arguments; ++i) {
-    HInstruction* value = LoadLocal(is_range ? register_index + i : args[i], type);
-    HInstruction* index = graph_->GetIntConstant(i);
+    HInstruction* value = LoadLocal(is_range ? register_index + i : args[i], type, dex_pc);
+    HInstruction* index = graph_->GetIntConstant(i, dex_pc);
     current_block_->AddInstruction(
         new (arena_) HArraySet(object, index, value, type, dex_pc));
   }
@@ -1469,8 +1466,8 @@
                                        Primitive::Type anticipated_type,
                                        uint32_t dex_pc) {
   for (uint32_t i = 0; i < element_count; ++i) {
-    HInstruction* index = graph_->GetIntConstant(i);
-    HInstruction* value = graph_->GetIntConstant(data[i]);
+    HInstruction* index = graph_->GetIntConstant(i, dex_pc);
+    HInstruction* value = graph_->GetIntConstant(data[i], dex_pc);
     current_block_->AddInstruction(new (arena_) HArraySet(
       object, index, value, anticipated_type, dex_pc));
   }
@@ -1478,12 +1475,12 @@
 
 void HGraphBuilder::BuildFillArrayData(const Instruction& instruction, uint32_t dex_pc) {
   Temporaries temps(graph_);
-  HInstruction* array = LoadLocal(instruction.VRegA_31t(), Primitive::kPrimNot);
+  HInstruction* array = LoadLocal(instruction.VRegA_31t(), Primitive::kPrimNot, dex_pc);
   HNullCheck* null_check = new (arena_) HNullCheck(array, dex_pc);
   current_block_->AddInstruction(null_check);
   temps.Add(null_check);
 
-  HInstruction* length = new (arena_) HArrayLength(null_check);
+  HInstruction* length = new (arena_) HArrayLength(null_check, dex_pc);
   current_block_->AddInstruction(length);
 
   int32_t payload_offset = instruction.VRegB_31t() + dex_pc;
@@ -1494,7 +1491,7 @@
 
   // Implementation of this DEX instruction seems to be that the bounds check is
   // done before doing any stores.
-  HInstruction* last_index = graph_->GetIntConstant(payload->element_count - 1);
+  HInstruction* last_index = graph_->GetIntConstant(payload->element_count - 1, dex_pc);
   current_block_->AddInstruction(new (arena_) HBoundsCheck(last_index, length, dex_pc));
 
   switch (payload->element_width) {
@@ -1536,8 +1533,8 @@
                                            uint32_t element_count,
                                            uint32_t dex_pc) {
   for (uint32_t i = 0; i < element_count; ++i) {
-    HInstruction* index = graph_->GetIntConstant(i);
-    HInstruction* value = graph_->GetLongConstant(data[i]);
+    HInstruction* index = graph_->GetIntConstant(i, dex_pc);
+    HInstruction* value = graph_->GetLongConstant(data[i], dex_pc);
     current_block_->AddInstruction(new (arena_) HArraySet(
       object, index, value, Primitive::kPrimLong, dex_pc));
   }
@@ -1562,7 +1559,7 @@
     MaybeRecordStat(MethodCompilationStat::kNotCompiledCantAccesType);
     return false;
   }
-  HInstruction* object = LoadLocal(reference, Primitive::kPrimNot);
+  HInstruction* object = LoadLocal(reference, Primitive::kPrimNot, dex_pc);
   HLoadClass* cls = new (arena_) HLoadClass(
       graph_->GetCurrentMethod(),
       type_index,
@@ -1576,7 +1573,7 @@
   if (instruction.Opcode() == Instruction::INSTANCE_OF) {
     current_block_->AddInstruction(
         new (arena_) HInstanceOf(object, cls, type_known_final, dex_pc));
-    UpdateLocal(destination, current_block_->GetLastInstruction());
+    UpdateLocal(destination, current_block_->GetLastInstruction(), dex_pc);
   } else {
     DCHECK_EQ(instruction.Opcode(), Instruction::CHECK_CAST);
     current_block_->AddInstruction(
@@ -1598,7 +1595,7 @@
   SwitchTable table(instruction, dex_pc, false);
 
   // Value to test against.
-  HInstruction* value = LoadLocal(instruction.VRegA(), Primitive::kPrimInt);
+  HInstruction* value = LoadLocal(instruction.VRegA(), Primitive::kPrimInt, dex_pc);
 
   // Retrieve number of entries.
   uint16_t num_entries = table.GetNumEntries();
@@ -1623,7 +1620,7 @@
   SwitchTable table(instruction, dex_pc, true);
 
   // Value to test against.
-  HInstruction* value = LoadLocal(instruction.VRegA(), Primitive::kPrimInt);
+  HInstruction* value = LoadLocal(instruction.VRegA(), Primitive::kPrimInt, dex_pc);
 
   uint16_t num_entries = table.GetNumEntries();
 
@@ -1642,12 +1639,12 @@
   PotentiallyAddSuspendCheck(case_target, dex_pc);
 
   // The current case's value.
-  HInstruction* this_case_value = graph_->GetIntConstant(case_value_int);
+  HInstruction* this_case_value = graph_->GetIntConstant(case_value_int, dex_pc);
 
   // Compare value and this_case_value.
-  HEqual* comparison = new (arena_) HEqual(value, this_case_value);
+  HEqual* comparison = new (arena_) HEqual(value, this_case_value, dex_pc);
   current_block_->AddInstruction(comparison);
-  HInstruction* ifinst = new (arena_) HIf(comparison);
+  HInstruction* ifinst = new (arena_) HIf(comparison, dex_pc);
   current_block_->AddInstruction(ifinst);
 
   // Case hit: use the target offset to determine where to go.
@@ -1711,29 +1708,29 @@
   switch (instruction.Opcode()) {
     case Instruction::CONST_4: {
       int32_t register_index = instruction.VRegA();
-      HIntConstant* constant = graph_->GetIntConstant(instruction.VRegB_11n());
-      UpdateLocal(register_index, constant);
+      HIntConstant* constant = graph_->GetIntConstant(instruction.VRegB_11n(), dex_pc);
+      UpdateLocal(register_index, constant, dex_pc);
       break;
     }
 
     case Instruction::CONST_16: {
       int32_t register_index = instruction.VRegA();
-      HIntConstant* constant = graph_->GetIntConstant(instruction.VRegB_21s());
-      UpdateLocal(register_index, constant);
+      HIntConstant* constant = graph_->GetIntConstant(instruction.VRegB_21s(), dex_pc);
+      UpdateLocal(register_index, constant, dex_pc);
       break;
     }
 
     case Instruction::CONST: {
       int32_t register_index = instruction.VRegA();
-      HIntConstant* constant = graph_->GetIntConstant(instruction.VRegB_31i());
-      UpdateLocal(register_index, constant);
+      HIntConstant* constant = graph_->GetIntConstant(instruction.VRegB_31i(), dex_pc);
+      UpdateLocal(register_index, constant, dex_pc);
       break;
     }
 
     case Instruction::CONST_HIGH16: {
       int32_t register_index = instruction.VRegA();
-      HIntConstant* constant = graph_->GetIntConstant(instruction.VRegB_21h() << 16);
-      UpdateLocal(register_index, constant);
+      HIntConstant* constant = graph_->GetIntConstant(instruction.VRegB_21h() << 16, dex_pc);
+      UpdateLocal(register_index, constant, dex_pc);
       break;
     }
 
@@ -1743,8 +1740,8 @@
       int64_t value = instruction.VRegB_21s();
       value <<= 48;
       value >>= 48;
-      HLongConstant* constant = graph_->GetLongConstant(value);
-      UpdateLocal(register_index, constant);
+      HLongConstant* constant = graph_->GetLongConstant(value, dex_pc);
+      UpdateLocal(register_index, constant, dex_pc);
       break;
     }
 
@@ -1754,23 +1751,23 @@
       int64_t value = instruction.VRegB_31i();
       value <<= 32;
       value >>= 32;
-      HLongConstant* constant = graph_->GetLongConstant(value);
-      UpdateLocal(register_index, constant);
+      HLongConstant* constant = graph_->GetLongConstant(value, dex_pc);
+      UpdateLocal(register_index, constant, dex_pc);
       break;
     }
 
     case Instruction::CONST_WIDE: {
       int32_t register_index = instruction.VRegA();
-      HLongConstant* constant = graph_->GetLongConstant(instruction.VRegB_51l());
-      UpdateLocal(register_index, constant);
+      HLongConstant* constant = graph_->GetLongConstant(instruction.VRegB_51l(), dex_pc);
+      UpdateLocal(register_index, constant, dex_pc);
       break;
     }
 
     case Instruction::CONST_WIDE_HIGH16: {
       int32_t register_index = instruction.VRegA();
       int64_t value = static_cast<int64_t>(instruction.VRegB_21h()) << 48;
-      HLongConstant* constant = graph_->GetLongConstant(value);
-      UpdateLocal(register_index, constant);
+      HLongConstant* constant = graph_->GetLongConstant(value, dex_pc);
+      UpdateLocal(register_index, constant, dex_pc);
       break;
     }
 
@@ -1778,8 +1775,8 @@
     case Instruction::MOVE:
     case Instruction::MOVE_FROM16:
     case Instruction::MOVE_16: {
-      HInstruction* value = LoadLocal(instruction.VRegB(), Primitive::kPrimInt);
-      UpdateLocal(instruction.VRegA(), value);
+      HInstruction* value = LoadLocal(instruction.VRegB(), Primitive::kPrimInt, dex_pc);
+      UpdateLocal(instruction.VRegA(), value, dex_pc);
       break;
     }
 
@@ -1787,22 +1784,22 @@
     case Instruction::MOVE_WIDE:
     case Instruction::MOVE_WIDE_FROM16:
     case Instruction::MOVE_WIDE_16: {
-      HInstruction* value = LoadLocal(instruction.VRegB(), Primitive::kPrimLong);
-      UpdateLocal(instruction.VRegA(), value);
+      HInstruction* value = LoadLocal(instruction.VRegB(), Primitive::kPrimLong, dex_pc);
+      UpdateLocal(instruction.VRegA(), value, dex_pc);
       break;
     }
 
     case Instruction::MOVE_OBJECT:
     case Instruction::MOVE_OBJECT_16:
     case Instruction::MOVE_OBJECT_FROM16: {
-      HInstruction* value = LoadLocal(instruction.VRegB(), Primitive::kPrimNot);
-      UpdateLocal(instruction.VRegA(), value);
+      HInstruction* value = LoadLocal(instruction.VRegB(), Primitive::kPrimNot, dex_pc);
+      UpdateLocal(instruction.VRegA(), value, dex_pc);
       break;
     }
 
     case Instruction::RETURN_VOID_NO_BARRIER:
     case Instruction::RETURN_VOID: {
-      BuildReturn(instruction, Primitive::kPrimVoid);
+      BuildReturn(instruction, Primitive::kPrimVoid, dex_pc);
       break;
     }
 
@@ -1824,24 +1821,24 @@
       HBasicBlock* target = FindBlockStartingAt(offset + dex_pc);
       DCHECK(target != nullptr);
       PotentiallyAddSuspendCheck(target, dex_pc);
-      current_block_->AddInstruction(new (arena_) HGoto());
+      current_block_->AddInstruction(new (arena_) HGoto(dex_pc));
       current_block_->AddSuccessor(target);
       current_block_ = nullptr;
       break;
     }
 
     case Instruction::RETURN: {
-      BuildReturn(instruction, return_type_);
+      BuildReturn(instruction, return_type_, dex_pc);
       break;
     }
 
     case Instruction::RETURN_OBJECT: {
-      BuildReturn(instruction, return_type_);
+      BuildReturn(instruction, return_type_, dex_pc);
       break;
     }
 
     case Instruction::RETURN_WIDE: {
-      BuildReturn(instruction, return_type_);
+      BuildReturn(instruction, return_type_, dex_pc);
       break;
     }
 
@@ -1895,32 +1892,32 @@
     }
 
     case Instruction::NEG_INT: {
-      Unop_12x<HNeg>(instruction, Primitive::kPrimInt);
+      Unop_12x<HNeg>(instruction, Primitive::kPrimInt, dex_pc);
       break;
     }
 
     case Instruction::NEG_LONG: {
-      Unop_12x<HNeg>(instruction, Primitive::kPrimLong);
+      Unop_12x<HNeg>(instruction, Primitive::kPrimLong, dex_pc);
       break;
     }
 
     case Instruction::NEG_FLOAT: {
-      Unop_12x<HNeg>(instruction, Primitive::kPrimFloat);
+      Unop_12x<HNeg>(instruction, Primitive::kPrimFloat, dex_pc);
       break;
     }
 
     case Instruction::NEG_DOUBLE: {
-      Unop_12x<HNeg>(instruction, Primitive::kPrimDouble);
+      Unop_12x<HNeg>(instruction, Primitive::kPrimDouble, dex_pc);
       break;
     }
 
     case Instruction::NOT_INT: {
-      Unop_12x<HNot>(instruction, Primitive::kPrimInt);
+      Unop_12x<HNot>(instruction, Primitive::kPrimInt, dex_pc);
       break;
     }
 
     case Instruction::NOT_LONG: {
-      Unop_12x<HNot>(instruction, Primitive::kPrimLong);
+      Unop_12x<HNot>(instruction, Primitive::kPrimLong, dex_pc);
       break;
     }
 
@@ -2000,67 +1997,67 @@
     }
 
     case Instruction::ADD_INT: {
-      Binop_23x<HAdd>(instruction, Primitive::kPrimInt);
+      Binop_23x<HAdd>(instruction, Primitive::kPrimInt, dex_pc);
       break;
     }
 
     case Instruction::ADD_LONG: {
-      Binop_23x<HAdd>(instruction, Primitive::kPrimLong);
+      Binop_23x<HAdd>(instruction, Primitive::kPrimLong, dex_pc);
       break;
     }
 
     case Instruction::ADD_DOUBLE: {
-      Binop_23x<HAdd>(instruction, Primitive::kPrimDouble);
+      Binop_23x<HAdd>(instruction, Primitive::kPrimDouble, dex_pc);
       break;
     }
 
     case Instruction::ADD_FLOAT: {
-      Binop_23x<HAdd>(instruction, Primitive::kPrimFloat);
+      Binop_23x<HAdd>(instruction, Primitive::kPrimFloat, dex_pc);
       break;
     }
 
     case Instruction::SUB_INT: {
-      Binop_23x<HSub>(instruction, Primitive::kPrimInt);
+      Binop_23x<HSub>(instruction, Primitive::kPrimInt, dex_pc);
       break;
     }
 
     case Instruction::SUB_LONG: {
-      Binop_23x<HSub>(instruction, Primitive::kPrimLong);
+      Binop_23x<HSub>(instruction, Primitive::kPrimLong, dex_pc);
       break;
     }
 
     case Instruction::SUB_FLOAT: {
-      Binop_23x<HSub>(instruction, Primitive::kPrimFloat);
+      Binop_23x<HSub>(instruction, Primitive::kPrimFloat, dex_pc);
       break;
     }
 
     case Instruction::SUB_DOUBLE: {
-      Binop_23x<HSub>(instruction, Primitive::kPrimDouble);
+      Binop_23x<HSub>(instruction, Primitive::kPrimDouble, dex_pc);
       break;
     }
 
     case Instruction::ADD_INT_2ADDR: {
-      Binop_12x<HAdd>(instruction, Primitive::kPrimInt);
+      Binop_12x<HAdd>(instruction, Primitive::kPrimInt, dex_pc);
       break;
     }
 
     case Instruction::MUL_INT: {
-      Binop_23x<HMul>(instruction, Primitive::kPrimInt);
+      Binop_23x<HMul>(instruction, Primitive::kPrimInt, dex_pc);
       break;
     }
 
     case Instruction::MUL_LONG: {
-      Binop_23x<HMul>(instruction, Primitive::kPrimLong);
+      Binop_23x<HMul>(instruction, Primitive::kPrimLong, dex_pc);
       break;
     }
 
     case Instruction::MUL_FLOAT: {
-      Binop_23x<HMul>(instruction, Primitive::kPrimFloat);
+      Binop_23x<HMul>(instruction, Primitive::kPrimFloat, dex_pc);
       break;
     }
 
     case Instruction::MUL_DOUBLE: {
-      Binop_23x<HMul>(instruction, Primitive::kPrimDouble);
+      Binop_23x<HMul>(instruction, Primitive::kPrimDouble, dex_pc);
       break;
     }
 
@@ -2109,117 +2106,117 @@
     }
 
     case Instruction::AND_INT: {
-      Binop_23x<HAnd>(instruction, Primitive::kPrimInt);
+      Binop_23x<HAnd>(instruction, Primitive::kPrimInt, dex_pc);
       break;
     }
 
     case Instruction::AND_LONG: {
-      Binop_23x<HAnd>(instruction, Primitive::kPrimLong);
+      Binop_23x<HAnd>(instruction, Primitive::kPrimLong, dex_pc);
       break;
     }
 
     case Instruction::SHL_INT: {
-      Binop_23x_shift<HShl>(instruction, Primitive::kPrimInt);
+      Binop_23x_shift<HShl>(instruction, Primitive::kPrimInt, dex_pc);
       break;
     }
 
     case Instruction::SHL_LONG: {
-      Binop_23x_shift<HShl>(instruction, Primitive::kPrimLong);
+      Binop_23x_shift<HShl>(instruction, Primitive::kPrimLong, dex_pc);
       break;
     }
 
     case Instruction::SHR_INT: {
-      Binop_23x_shift<HShr>(instruction, Primitive::kPrimInt);
+      Binop_23x_shift<HShr>(instruction, Primitive::kPrimInt, dex_pc);
       break;
     }
 
     case Instruction::SHR_LONG: {
-      Binop_23x_shift<HShr>(instruction, Primitive::kPrimLong);
+      Binop_23x_shift<HShr>(instruction, Primitive::kPrimLong, dex_pc);
       break;
     }
 
     case Instruction::USHR_INT: {
-      Binop_23x_shift<HUShr>(instruction, Primitive::kPrimInt);
+      Binop_23x_shift<HUShr>(instruction, Primitive::kPrimInt, dex_pc);
       break;
     }
 
     case Instruction::USHR_LONG: {
-      Binop_23x_shift<HUShr>(instruction, Primitive::kPrimLong);
+      Binop_23x_shift<HUShr>(instruction, Primitive::kPrimLong, dex_pc);
       break;
     }
 
     case Instruction::OR_INT: {
-      Binop_23x<HOr>(instruction, Primitive::kPrimInt);
+      Binop_23x<HOr>(instruction, Primitive::kPrimInt, dex_pc);
       break;
     }
 
     case Instruction::OR_LONG: {
-      Binop_23x<HOr>(instruction, Primitive::kPrimLong);
+      Binop_23x<HOr>(instruction, Primitive::kPrimLong, dex_pc);
       break;
     }
 
     case Instruction::XOR_INT: {
-      Binop_23x<HXor>(instruction, Primitive::kPrimInt);
+      Binop_23x<HXor>(instruction, Primitive::kPrimInt, dex_pc);
       break;
     }
 
     case Instruction::XOR_LONG: {
-      Binop_23x<HXor>(instruction, Primitive::kPrimLong);
+      Binop_23x<HXor>(instruction, Primitive::kPrimLong, dex_pc);
       break;
     }
 
     case Instruction::ADD_LONG_2ADDR: {
-      Binop_12x<HAdd>(instruction, Primitive::kPrimLong);
+      Binop_12x<HAdd>(instruction, Primitive::kPrimLong, dex_pc);
       break;
     }
 
     case Instruction::ADD_DOUBLE_2ADDR: {
-      Binop_12x<HAdd>(instruction, Primitive::kPrimDouble);
+      Binop_12x<HAdd>(instruction, Primitive::kPrimDouble, dex_pc);
       break;
     }
 
     case Instruction::ADD_FLOAT_2ADDR: {
-      Binop_12x<HAdd>(instruction, Primitive::kPrimFloat);
+      Binop_12x<HAdd>(instruction, Primitive::kPrimFloat, dex_pc);
       break;
     }
 
     case Instruction::SUB_INT_2ADDR: {
-      Binop_12x<HSub>(instruction, Primitive::kPrimInt);
+      Binop_12x<HSub>(instruction, Primitive::kPrimInt, dex_pc);
       break;
     }
 
     case Instruction::SUB_LONG_2ADDR: {
-      Binop_12x<HSub>(instruction, Primitive::kPrimLong);
+      Binop_12x<HSub>(instruction, Primitive::kPrimLong, dex_pc);
       break;
     }
 
     case Instruction::SUB_FLOAT_2ADDR: {
-      Binop_12x<HSub>(instruction, Primitive::kPrimFloat);
+      Binop_12x<HSub>(instruction, Primitive::kPrimFloat, dex_pc);
       break;
     }
 
     case Instruction::SUB_DOUBLE_2ADDR: {
-      Binop_12x<HSub>(instruction, Primitive::kPrimDouble);
+      Binop_12x<HSub>(instruction, Primitive::kPrimDouble, dex_pc);
       break;
     }
 
     case Instruction::MUL_INT_2ADDR: {
-      Binop_12x<HMul>(instruction, Primitive::kPrimInt);
+      Binop_12x<HMul>(instruction, Primitive::kPrimInt, dex_pc);
       break;
     }
 
     case Instruction::MUL_LONG_2ADDR: {
-      Binop_12x<HMul>(instruction, Primitive::kPrimLong);
+      Binop_12x<HMul>(instruction, Primitive::kPrimLong, dex_pc);
       break;
     }
 
     case Instruction::MUL_FLOAT_2ADDR: {
-      Binop_12x<HMul>(instruction, Primitive::kPrimFloat);
+      Binop_12x<HMul>(instruction, Primitive::kPrimFloat, dex_pc);
       break;
     }
 
     case Instruction::MUL_DOUBLE_2ADDR: {
-      Binop_12x<HMul>(instruction, Primitive::kPrimDouble);
+      Binop_12x<HMul>(instruction, Primitive::kPrimDouble, dex_pc);
       break;
     }
 
@@ -2258,32 +2255,32 @@
     }
 
     case Instruction::SHL_INT_2ADDR: {
-      Binop_12x_shift<HShl>(instruction, Primitive::kPrimInt);
+      Binop_12x_shift<HShl>(instruction, Primitive::kPrimInt, dex_pc);
       break;
     }
 
     case Instruction::SHL_LONG_2ADDR: {
-      Binop_12x_shift<HShl>(instruction, Primitive::kPrimLong);
+      Binop_12x_shift<HShl>(instruction, Primitive::kPrimLong, dex_pc);
       break;
     }
 
     case Instruction::SHR_INT_2ADDR: {
-      Binop_12x_shift<HShr>(instruction, Primitive::kPrimInt);
+      Binop_12x_shift<HShr>(instruction, Primitive::kPrimInt, dex_pc);
       break;
     }
 
     case Instruction::SHR_LONG_2ADDR: {
-      Binop_12x_shift<HShr>(instruction, Primitive::kPrimLong);
+      Binop_12x_shift<HShr>(instruction, Primitive::kPrimLong, dex_pc);
       break;
     }
 
     case Instruction::USHR_INT_2ADDR: {
-      Binop_12x_shift<HUShr>(instruction, Primitive::kPrimInt);
+      Binop_12x_shift<HUShr>(instruction, Primitive::kPrimInt, dex_pc);
       break;
     }
 
     case Instruction::USHR_LONG_2ADDR: {
-      Binop_12x_shift<HUShr>(instruction, Primitive::kPrimLong);
+      Binop_12x_shift<HUShr>(instruction, Primitive::kPrimLong, dex_pc);
       break;
     }
 
@@ -2298,92 +2295,92 @@
     }
 
     case Instruction::AND_INT_2ADDR: {
-      Binop_12x<HAnd>(instruction, Primitive::kPrimInt);
+      Binop_12x<HAnd>(instruction, Primitive::kPrimInt, dex_pc);
       break;
     }
 
     case Instruction::AND_LONG_2ADDR: {
-      Binop_12x<HAnd>(instruction, Primitive::kPrimLong);
+      Binop_12x<HAnd>(instruction, Primitive::kPrimLong, dex_pc);
       break;
     }
 
     case Instruction::OR_INT_2ADDR: {
-      Binop_12x<HOr>(instruction, Primitive::kPrimInt);
+      Binop_12x<HOr>(instruction, Primitive::kPrimInt, dex_pc);
       break;
     }
 
     case Instruction::OR_LONG_2ADDR: {
-      Binop_12x<HOr>(instruction, Primitive::kPrimLong);
+      Binop_12x<HOr>(instruction, Primitive::kPrimLong, dex_pc);
       break;
     }
 
     case Instruction::XOR_INT_2ADDR: {
-      Binop_12x<HXor>(instruction, Primitive::kPrimInt);
+      Binop_12x<HXor>(instruction, Primitive::kPrimInt, dex_pc);
       break;
     }
 
     case Instruction::XOR_LONG_2ADDR: {
-      Binop_12x<HXor>(instruction, Primitive::kPrimLong);
+      Binop_12x<HXor>(instruction, Primitive::kPrimLong, dex_pc);
       break;
     }
 
     case Instruction::ADD_INT_LIT16: {
-      Binop_22s<HAdd>(instruction, false);
+      Binop_22s<HAdd>(instruction, false, dex_pc);
       break;
     }
 
     case Instruction::AND_INT_LIT16: {
-      Binop_22s<HAnd>(instruction, false);
+      Binop_22s<HAnd>(instruction, false, dex_pc);
       break;
     }
 
     case Instruction::OR_INT_LIT16: {
-      Binop_22s<HOr>(instruction, false);
+      Binop_22s<HOr>(instruction, false, dex_pc);
       break;
     }
 
     case Instruction::XOR_INT_LIT16: {
-      Binop_22s<HXor>(instruction, false);
+      Binop_22s<HXor>(instruction, false, dex_pc);
       break;
     }
 
     case Instruction::RSUB_INT: {
-      Binop_22s<HSub>(instruction, true);
+      Binop_22s<HSub>(instruction, true, dex_pc);
       break;
     }
 
     case Instruction::MUL_INT_LIT16: {
-      Binop_22s<HMul>(instruction, false);
+      Binop_22s<HMul>(instruction, false, dex_pc);
       break;
     }
 
     case Instruction::ADD_INT_LIT8: {
-      Binop_22b<HAdd>(instruction, false);
+      Binop_22b<HAdd>(instruction, false, dex_pc);
       break;
     }
 
     case Instruction::AND_INT_LIT8: {
-      Binop_22b<HAnd>(instruction, false);
+      Binop_22b<HAnd>(instruction, false, dex_pc);
       break;
     }
 
     case Instruction::OR_INT_LIT8: {
-      Binop_22b<HOr>(instruction, false);
+      Binop_22b<HOr>(instruction, false, dex_pc);
       break;
     }
 
     case Instruction::XOR_INT_LIT8: {
-      Binop_22b<HXor>(instruction, false);
+      Binop_22b<HXor>(instruction, false, dex_pc);
       break;
     }
 
     case Instruction::RSUB_INT_LIT8: {
-      Binop_22b<HSub>(instruction, true);
+      Binop_22b<HSub>(instruction, true, dex_pc);
       break;
     }
 
     case Instruction::MUL_INT_LIT8: {
-      Binop_22b<HMul>(instruction, false);
+      Binop_22b<HMul>(instruction, false, dex_pc);
       break;
     }
 
@@ -2402,17 +2399,17 @@
     }
 
     case Instruction::SHL_INT_LIT8: {
-      Binop_22b<HShl>(instruction, false);
+      Binop_22b<HShl>(instruction, false, dex_pc);
       break;
     }
 
     case Instruction::SHR_INT_LIT8: {
-      Binop_22b<HShr>(instruction, false);
+      Binop_22b<HShr>(instruction, false, dex_pc);
       break;
     }
 
     case Instruction::USHR_INT_LIT8: {
-      Binop_22b<HUShr>(instruction, false);
+      Binop_22b<HUShr>(instruction, false, dex_pc);
       break;
     }
 
@@ -2420,9 +2417,9 @@
       uint16_t type_index = instruction.VRegB_21c();
       if (compiler_driver_->IsStringTypeIndex(type_index, dex_file_)) {
         int32_t register_index = instruction.VRegA();
-        HFakeString* fake_string = new (arena_) HFakeString();
+        HFakeString* fake_string = new (arena_) HFakeString(dex_pc);
         current_block_->AddInstruction(fake_string);
-        UpdateLocal(register_index, fake_string);
+        UpdateLocal(register_index, fake_string, dex_pc);
       } else {
         QuickEntrypointEnum entrypoint = NeedsAccessCheck(type_index)
             ? kQuickAllocObjectWithAccessCheck
@@ -2434,14 +2431,14 @@
             type_index,
             *dex_compilation_unit_->GetDexFile(),
             entrypoint));
-        UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction());
+        UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction(), dex_pc);
       }
       break;
     }
 
     case Instruction::NEW_ARRAY: {
       uint16_t type_index = instruction.VRegC_22c();
-      HInstruction* length = LoadLocal(instruction.VRegB_22c(), Primitive::kPrimInt);
+      HInstruction* length = LoadLocal(instruction.VRegB_22c(), Primitive::kPrimInt, dex_pc);
       QuickEntrypointEnum entrypoint = NeedsAccessCheck(type_index)
           ? kQuickAllocArrayWithAccessCheck
           : kQuickAllocArray;
@@ -2451,7 +2448,7 @@
                                                             type_index,
                                                             *dex_compilation_unit_->GetDexFile(),
                                                             entrypoint));
-      UpdateLocal(instruction.VRegA_22c(), current_block_->GetLastInstruction());
+      UpdateLocal(instruction.VRegA_22c(), current_block_->GetLastInstruction(), dex_pc);
       break;
     }
 
@@ -2491,7 +2488,7 @@
         // FilledNewArray, the local needs to be updated after the array was
         // filled, otherwise we might overwrite an input vreg.
         HStoreLocal* update_local =
-            new (arena_) HStoreLocal(GetLocalAt(instruction.VRegA()), latest_result_);
+            new (arena_) HStoreLocal(GetLocalAt(instruction.VRegA()), latest_result_, dex_pc);
         HBasicBlock* block = latest_result_->GetBlock();
         if (block == current_block_) {
           // MoveResult and the previous instruction are in the same block.
@@ -2621,27 +2618,27 @@
     ARRAY_XX(_SHORT, Primitive::kPrimShort);
 
     case Instruction::ARRAY_LENGTH: {
-      HInstruction* object = LoadLocal(instruction.VRegB_12x(), Primitive::kPrimNot);
+      HInstruction* object = LoadLocal(instruction.VRegB_12x(), Primitive::kPrimNot, dex_pc);
       // No need for a temporary for the null check, it is the only input of the following
       // instruction.
       object = new (arena_) HNullCheck(object, dex_pc);
       current_block_->AddInstruction(object);
-      current_block_->AddInstruction(new (arena_) HArrayLength(object));
-      UpdateLocal(instruction.VRegA_12x(), current_block_->GetLastInstruction());
+      current_block_->AddInstruction(new (arena_) HArrayLength(object, dex_pc));
+      UpdateLocal(instruction.VRegA_12x(), current_block_->GetLastInstruction(), dex_pc);
       break;
     }
 
     case Instruction::CONST_STRING: {
       current_block_->AddInstruction(
           new (arena_) HLoadString(graph_->GetCurrentMethod(), instruction.VRegB_21c(), dex_pc));
-      UpdateLocal(instruction.VRegA_21c(), current_block_->GetLastInstruction());
+      UpdateLocal(instruction.VRegA_21c(), current_block_->GetLastInstruction(), dex_pc);
       break;
     }
 
     case Instruction::CONST_STRING_JUMBO: {
       current_block_->AddInstruction(
           new (arena_) HLoadString(graph_->GetCurrentMethod(), instruction.VRegB_31c(), dex_pc));
-      UpdateLocal(instruction.VRegA_31c(), current_block_->GetLastInstruction());
+      UpdateLocal(instruction.VRegA_31c(), current_block_->GetLastInstruction(), dex_pc);
       break;
     }
 
@@ -2667,19 +2664,19 @@
           *dex_compilation_unit_->GetDexFile(),
           IsOutermostCompilingClass(type_index),
           dex_pc));
-      UpdateLocal(instruction.VRegA_21c(), current_block_->GetLastInstruction());
+      UpdateLocal(instruction.VRegA_21c(), current_block_->GetLastInstruction(), dex_pc);
       break;
     }
 
     case Instruction::MOVE_EXCEPTION: {
-      current_block_->AddInstruction(new (arena_) HLoadException());
-      UpdateLocal(instruction.VRegA_11x(), current_block_->GetLastInstruction());
-      current_block_->AddInstruction(new (arena_) HClearException());
+      current_block_->AddInstruction(new (arena_) HLoadException(dex_pc));
+      UpdateLocal(instruction.VRegA_11x(), current_block_->GetLastInstruction(), dex_pc);
+      current_block_->AddInstruction(new (arena_) HClearException(dex_pc));
       break;
     }
 
     case Instruction::THROW: {
-      HInstruction* exception = LoadLocal(instruction.VRegA_11x(), Primitive::kPrimNot);
+      HInstruction* exception = LoadLocal(instruction.VRegA_11x(), Primitive::kPrimNot, dex_pc);
       current_block_->AddInstruction(new (arena_) HThrow(exception, dex_pc));
       // A throw instruction must branch to the exit block.
       current_block_->AddSuccessor(exit_block_);
@@ -2710,7 +2707,7 @@
 
     case Instruction::MONITOR_ENTER: {
       current_block_->AddInstruction(new (arena_) HMonitorOperation(
-          LoadLocal(instruction.VRegA_11x(), Primitive::kPrimNot),
+          LoadLocal(instruction.VRegA_11x(), Primitive::kPrimNot, dex_pc),
           HMonitorOperation::kEnter,
           dex_pc));
       break;
@@ -2718,7 +2715,7 @@
 
     case Instruction::MONITOR_EXIT: {
       current_block_->AddInstruction(new (arena_) HMonitorOperation(
-          LoadLocal(instruction.VRegA_11x(), Primitive::kPrimNot),
+          LoadLocal(instruction.VRegA_11x(), Primitive::kPrimNot, dex_pc),
           HMonitorOperation::kExit,
           dex_pc));
       break;
@@ -2749,14 +2746,18 @@
   return locals_.Get(register_index);
 }
 
-void HGraphBuilder::UpdateLocal(int register_index, HInstruction* instruction) const {
+void HGraphBuilder::UpdateLocal(int register_index,
+                                HInstruction* instruction,
+                                uint32_t dex_pc) const {
   HLocal* local = GetLocalAt(register_index);
-  current_block_->AddInstruction(new (arena_) HStoreLocal(local, instruction));
+  current_block_->AddInstruction(new (arena_) HStoreLocal(local, instruction, dex_pc));
 }
 
-HInstruction* HGraphBuilder::LoadLocal(int register_index, Primitive::Type type) const {
+HInstruction* HGraphBuilder::LoadLocal(int register_index,
+                                       Primitive::Type type,
+                                       uint32_t dex_pc) const {
   HLocal* local = GetLocalAt(register_index);
-  current_block_->AddInstruction(new (arena_) HLoadLocal(local, type));
+  current_block_->AddInstruction(new (arena_) HLoadLocal(local, type, dex_pc));
   return current_block_->GetLastInstruction();
 }
 
diff --git a/compiler/optimizing/builder.h b/compiler/optimizing/builder.h
index 560ed86..b0238dc 100644
--- a/compiler/optimizing/builder.h
+++ b/compiler/optimizing/builder.h
@@ -131,23 +131,20 @@
 
   void InitializeLocals(uint16_t count);
   HLocal* GetLocalAt(int register_index) const;
-  void UpdateLocal(int register_index, HInstruction* instruction) const;
-  HInstruction* LoadLocal(int register_index, Primitive::Type type) const;
+  void UpdateLocal(int register_index, HInstruction* instruction, uint32_t dex_pc) const;
+  HInstruction* LoadLocal(int register_index, Primitive::Type type, uint32_t dex_pc) const;
   void PotentiallyAddSuspendCheck(HBasicBlock* target, uint32_t dex_pc);
   void InitializeParameters(uint16_t number_of_parameters);
   bool NeedsAccessCheck(uint32_t type_index) const;
 
   template<typename T>
-  void Unop_12x(const Instruction& instruction, Primitive::Type type);
-
-  template<typename T>
-  void Binop_23x(const Instruction& instruction, Primitive::Type type);
+  void Unop_12x(const Instruction& instruction, Primitive::Type type, uint32_t dex_pc);
 
   template<typename T>
   void Binop_23x(const Instruction& instruction, Primitive::Type type, uint32_t dex_pc);
 
   template<typename T>
-  void Binop_23x_shift(const Instruction& instruction, Primitive::Type type);
+  void Binop_23x_shift(const Instruction& instruction, Primitive::Type type, uint32_t dex_pc);
 
   void Binop_23x_cmp(const Instruction& instruction,
                      Primitive::Type type,
@@ -155,19 +152,16 @@
                      uint32_t dex_pc);
 
   template<typename T>
-  void Binop_12x(const Instruction& instruction, Primitive::Type type);
-
-  template<typename T>
   void Binop_12x(const Instruction& instruction, Primitive::Type type, uint32_t dex_pc);
 
   template<typename T>
-  void Binop_12x_shift(const Instruction& instruction, Primitive::Type type);
+  void Binop_12x_shift(const Instruction& instruction, Primitive::Type type, uint32_t dex_pc);
 
   template<typename T>
-  void Binop_22b(const Instruction& instruction, bool reverse);
+  void Binop_22b(const Instruction& instruction, bool reverse, uint32_t dex_pc);
 
   template<typename T>
-  void Binop_22s(const Instruction& instruction, bool reverse);
+  void Binop_22s(const Instruction& instruction, bool reverse, uint32_t dex_pc);
 
   template<typename T> void If_21t(const Instruction& instruction, uint32_t dex_pc);
   template<typename T> void If_22t(const Instruction& instruction, uint32_t dex_pc);
@@ -185,7 +179,7 @@
                           bool second_is_lit,
                           bool is_div);
 
-  void BuildReturn(const Instruction& instruction, Primitive::Type type);
+  void BuildReturn(const Instruction& instruction, Primitive::Type type, uint32_t dex_pc);
 
   // Builds an instance field access node and returns whether the instruction is supported.
   bool BuildInstanceFieldAccess(const Instruction& instruction, uint32_t dex_pc, bool is_put);
diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc
index 679899a..438ef69 100644
--- a/compiler/optimizing/code_generator_arm.cc
+++ b/compiler/optimizing/code_generator_arm.cc
@@ -1560,25 +1560,7 @@
     return;
   }
 
-  Register temp = invoke->GetLocations()->GetTemp(0).AsRegister<Register>();
-  uint32_t method_offset = mirror::Class::EmbeddedVTableEntryOffset(
-      invoke->GetVTableIndex(), kArmPointerSize).Uint32Value();
-  LocationSummary* locations = invoke->GetLocations();
-  Location receiver = locations->InAt(0);
-  uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
-  // temp = object->GetClass();
-  DCHECK(receiver.IsRegister());
-  __ LoadFromOffset(kLoadWord, temp, receiver.AsRegister<Register>(), class_offset);
-  codegen_->MaybeRecordImplicitNullCheck(invoke);
-  __ MaybeUnpoisonHeapReference(temp);
-  // temp = temp->GetMethodAt(method_offset);
-  uint32_t entry_point = ArtMethod::EntryPointFromQuickCompiledCodeOffset(
-      kArmWordSize).Int32Value();
-  __ LoadFromOffset(kLoadWord, temp, temp, method_offset);
-  // LR = temp->GetEntryPoint();
-  __ LoadFromOffset(kLoadWord, LR, temp, entry_point);
-  // LR();
-  __ blx(LR);
+  codegen_->GenerateVirtualCall(invoke, invoke->GetLocations()->GetTemp(0));
   DCHECK(!codegen_->IsLeafMethod());
   codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
 }
@@ -4607,6 +4589,28 @@
   DCHECK(!IsLeafMethod());
 }
 
+void CodeGeneratorARM::GenerateVirtualCall(HInvokeVirtual* invoke, Location temp_location) {
+  Register temp = temp_location.AsRegister<Register>();
+  uint32_t method_offset = mirror::Class::EmbeddedVTableEntryOffset(
+      invoke->GetVTableIndex(), kArmPointerSize).Uint32Value();
+  LocationSummary* locations = invoke->GetLocations();
+  Location receiver = locations->InAt(0);
+  uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
+  // temp = object->GetClass();
+  DCHECK(receiver.IsRegister());
+  __ LoadFromOffset(kLoadWord, temp, receiver.AsRegister<Register>(), class_offset);
+  MaybeRecordImplicitNullCheck(invoke);
+  __ MaybeUnpoisonHeapReference(temp);
+  // temp = temp->GetMethodAt(method_offset);
+  uint32_t entry_point = ArtMethod::EntryPointFromQuickCompiledCodeOffset(
+      kArmWordSize).Int32Value();
+  __ LoadFromOffset(kLoadWord, temp, temp, method_offset);
+  // LR = temp->GetEntryPoint();
+  __ LoadFromOffset(kLoadWord, LR, temp, entry_point);
+  // LR();
+  __ blx(LR);
+}
+
 void CodeGeneratorARM::EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patches) {
   DCHECK(linker_patches->empty());
   size_t size = method_patches_.size() + call_patches_.size() + relative_call_patches_.size();
diff --git a/compiler/optimizing/code_generator_arm.h b/compiler/optimizing/code_generator_arm.h
index 9528cca..4a0df4e 100644
--- a/compiler/optimizing/code_generator_arm.h
+++ b/compiler/optimizing/code_generator_arm.h
@@ -327,6 +327,7 @@
   Label* GetFrameEntryLabel() { return &frame_entry_label_; }
 
   void GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp);
+  void GenerateVirtualCall(HInvokeVirtual* invoke, Location temp);
 
   void EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patches) OVERRIDE;
 
diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc
index 390ea6b..6b1457b 100644
--- a/compiler/optimizing/code_generator_arm64.cc
+++ b/compiler/optimizing/code_generator_arm64.cc
@@ -2474,6 +2474,29 @@
   DCHECK(!IsLeafMethod());
 }
 
+void CodeGeneratorARM64::GenerateVirtualCall(HInvokeVirtual* invoke, Location temp_in) {
+  LocationSummary* locations = invoke->GetLocations();
+  Location receiver = locations->InAt(0);
+  Register temp = XRegisterFrom(temp_in);
+  size_t method_offset = mirror::Class::EmbeddedVTableEntryOffset(
+      invoke->GetVTableIndex(), kArm64PointerSize).SizeValue();
+  Offset class_offset = mirror::Object::ClassOffset();
+  Offset entry_point = ArtMethod::EntryPointFromQuickCompiledCodeOffset(kArm64WordSize);
+
+  BlockPoolsScope block_pools(GetVIXLAssembler());
+
+  DCHECK(receiver.IsRegister());
+  __ Ldr(temp.W(), HeapOperandFrom(receiver, class_offset));
+  MaybeRecordImplicitNullCheck(invoke);
+  GetAssembler()->MaybeUnpoisonHeapReference(temp.W());
+  // temp = temp->GetMethodAt(method_offset);
+  __ Ldr(temp, MemOperand(temp, method_offset));
+  // lr = temp->GetEntryPoint();
+  __ Ldr(lr, MemOperand(temp, entry_point.SizeValue()));
+  // lr();
+  __ Blr(lr);
+}
+
 void CodeGeneratorARM64::EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patches) {
   DCHECK(linker_patches->empty());
   size_t size =
@@ -2567,26 +2590,7 @@
     return;
   }
 
-  LocationSummary* locations = invoke->GetLocations();
-  Location receiver = locations->InAt(0);
-  Register temp = XRegisterFrom(invoke->GetLocations()->GetTemp(0));
-  size_t method_offset = mirror::Class::EmbeddedVTableEntryOffset(
-      invoke->GetVTableIndex(), kArm64PointerSize).SizeValue();
-  Offset class_offset = mirror::Object::ClassOffset();
-  Offset entry_point = ArtMethod::EntryPointFromQuickCompiledCodeOffset(kArm64WordSize);
-
-  BlockPoolsScope block_pools(GetVIXLAssembler());
-
-  DCHECK(receiver.IsRegister());
-  __ Ldr(temp.W(), HeapOperandFrom(receiver, class_offset));
-  codegen_->MaybeRecordImplicitNullCheck(invoke);
-  GetAssembler()->MaybeUnpoisonHeapReference(temp.W());
-  // temp = temp->GetMethodAt(method_offset);
-  __ Ldr(temp, MemOperand(temp, method_offset));
-  // lr = temp->GetEntryPoint();
-  __ Ldr(lr, MemOperand(temp, entry_point.SizeValue()));
-  // lr();
-  __ Blr(lr);
+  codegen_->GenerateVirtualCall(invoke, invoke->GetLocations()->GetTemp(0));
   DCHECK(!codegen_->IsLeafMethod());
   codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
 }
diff --git a/compiler/optimizing/code_generator_arm64.h b/compiler/optimizing/code_generator_arm64.h
index 18070fc..12ead7e 100644
--- a/compiler/optimizing/code_generator_arm64.h
+++ b/compiler/optimizing/code_generator_arm64.h
@@ -359,6 +359,7 @@
   }
 
   void GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp);
+  void GenerateVirtualCall(HInvokeVirtual* invoke, Location temp);
 
   void EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patches) OVERRIDE;
 
diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc
index f48395b..a5ad226 100644
--- a/compiler/optimizing/code_generator_x86.cc
+++ b/compiler/optimizing/code_generator_x86.cc
@@ -19,6 +19,7 @@
 #include "art_method.h"
 #include "code_generator_utils.h"
 #include "compiled_method.h"
+#include "constant_area_fixups_x86.h"
 #include "entrypoints/quick/quick_entrypoints.h"
 #include "entrypoints/quick/quick_entrypoints_enum.h"
 #include "gc/accounting/card_table.h"
@@ -1548,23 +1549,11 @@
 }
 
 void InstructionCodeGeneratorX86::VisitInvokeVirtual(HInvokeVirtual* invoke) {
-  Register temp = invoke->GetLocations()->GetTemp(0).AsRegister<Register>();
-  uint32_t method_offset = mirror::Class::EmbeddedVTableEntryOffset(
-      invoke->GetVTableIndex(), kX86PointerSize).Uint32Value();
-  LocationSummary* locations = invoke->GetLocations();
-  Location receiver = locations->InAt(0);
-  uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
-  // temp = object->GetClass();
-  DCHECK(receiver.IsRegister());
-  __ movl(temp, Address(receiver.AsRegister<Register>(), class_offset));
-  codegen_->MaybeRecordImplicitNullCheck(invoke);
-  __ MaybeUnpoisonHeapReference(temp);
-  // temp = temp->GetMethodAt(method_offset);
-  __ movl(temp, Address(temp, method_offset));
-  // call temp->GetEntryPoint();
-  __ call(Address(
-      temp, ArtMethod::EntryPointFromQuickCompiledCodeOffset(kX86WordSize).Int32Value()));
+  if (TryGenerateIntrinsicCode(invoke, codegen_)) {
+    return;
+  }
 
+  codegen_->GenerateVirtualCall(invoke, invoke->GetLocations()->GetTemp(0));
   DCHECK(!codegen_->IsLeafMethod());
   codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
 }
@@ -2213,7 +2202,7 @@
     case Primitive::kPrimFloat:
     case Primitive::kPrimDouble: {
       locations->SetInAt(0, Location::RequiresFpuRegister());
-      locations->SetInAt(1, Location::RequiresFpuRegister());
+      locations->SetInAt(1, Location::Any());
       locations->SetOut(Location::SameAsFirstInput());
       break;
     }
@@ -2275,6 +2264,16 @@
     case Primitive::kPrimFloat: {
       if (second.IsFpuRegister()) {
         __ addss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
+      } else if (add->InputAt(1)->IsX86LoadFromConstantTable()) {
+        HX86LoadFromConstantTable* const_area = add->InputAt(1)->AsX86LoadFromConstantTable();
+        DCHECK(!const_area->NeedsMaterialization());
+        __ addss(first.AsFpuRegister<XmmRegister>(),
+                 codegen_->LiteralFloatAddress(
+                   const_area->GetConstant()->AsFloatConstant()->GetValue(),
+                   const_area->GetLocations()->InAt(0).AsRegister<Register>()));
+      } else {
+        DCHECK(second.IsStackSlot());
+        __ addss(first.AsFpuRegister<XmmRegister>(), Address(ESP, second.GetStackIndex()));
       }
       break;
     }
@@ -2282,6 +2281,16 @@
     case Primitive::kPrimDouble: {
       if (second.IsFpuRegister()) {
         __ addsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
+      } else if (add->InputAt(1)->IsX86LoadFromConstantTable()) {
+        HX86LoadFromConstantTable* const_area = add->InputAt(1)->AsX86LoadFromConstantTable();
+        DCHECK(!const_area->NeedsMaterialization());
+        __ addsd(first.AsFpuRegister<XmmRegister>(),
+                 codegen_->LiteralDoubleAddress(
+                   const_area->GetConstant()->AsDoubleConstant()->GetValue(),
+                   const_area->GetLocations()->InAt(0).AsRegister<Register>()));
+      } else {
+        DCHECK(second.IsDoubleStackSlot());
+        __ addsd(first.AsFpuRegister<XmmRegister>(), Address(ESP, second.GetStackIndex()));
       }
       break;
     }
@@ -2305,7 +2314,7 @@
     case Primitive::kPrimFloat:
     case Primitive::kPrimDouble: {
       locations->SetInAt(0, Location::RequiresFpuRegister());
-      locations->SetInAt(1, Location::RequiresFpuRegister());
+      locations->SetInAt(1, Location::Any());
       locations->SetOut(Location::SameAsFirstInput());
       break;
     }
@@ -2351,12 +2360,36 @@
     }
 
     case Primitive::kPrimFloat: {
-      __ subss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
+      if (second.IsFpuRegister()) {
+        __ subss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
+      } else if (sub->InputAt(1)->IsX86LoadFromConstantTable()) {
+        HX86LoadFromConstantTable* const_area = sub->InputAt(1)->AsX86LoadFromConstantTable();
+        DCHECK(!const_area->NeedsMaterialization());
+        __ subss(first.AsFpuRegister<XmmRegister>(),
+                 codegen_->LiteralFloatAddress(
+                   const_area->GetConstant()->AsFloatConstant()->GetValue(),
+                   const_area->GetLocations()->InAt(0).AsRegister<Register>()));
+      } else {
+        DCHECK(second.IsStackSlot());
+        __ subss(first.AsFpuRegister<XmmRegister>(), Address(ESP, second.GetStackIndex()));
+      }
       break;
     }
 
     case Primitive::kPrimDouble: {
-      __ subsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
+      if (second.IsFpuRegister()) {
+        __ subsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
+      } else if (sub->InputAt(1)->IsX86LoadFromConstantTable()) {
+        HX86LoadFromConstantTable* const_area = sub->InputAt(1)->AsX86LoadFromConstantTable();
+        DCHECK(!const_area->NeedsMaterialization());
+        __ subsd(first.AsFpuRegister<XmmRegister>(),
+                 codegen_->LiteralDoubleAddress(
+                     const_area->GetConstant()->AsDoubleConstant()->GetValue(),
+                     const_area->GetLocations()->InAt(0).AsRegister<Register>()));
+      } else {
+        DCHECK(second.IsDoubleStackSlot());
+        __ subsd(first.AsFpuRegister<XmmRegister>(), Address(ESP, second.GetStackIndex()));
+      }
       break;
     }
 
@@ -2391,7 +2424,7 @@
     case Primitive::kPrimFloat:
     case Primitive::kPrimDouble: {
       locations->SetInAt(0, Location::RequiresFpuRegister());
-      locations->SetInAt(1, Location::RequiresFpuRegister());
+      locations->SetInAt(1, Location::Any());
       locations->SetOut(Location::SameAsFirstInput());
       break;
     }
@@ -2507,12 +2540,38 @@
     }
 
     case Primitive::kPrimFloat: {
-      __ mulss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
+      DCHECK(first.Equals(locations->Out()));
+      if (second.IsFpuRegister()) {
+        __ mulss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
+      } else if (mul->InputAt(1)->IsX86LoadFromConstantTable()) {
+        HX86LoadFromConstantTable* const_area = mul->InputAt(1)->AsX86LoadFromConstantTable();
+        DCHECK(!const_area->NeedsMaterialization());
+        __ mulss(first.AsFpuRegister<XmmRegister>(),
+                 codegen_->LiteralFloatAddress(
+                     const_area->GetConstant()->AsFloatConstant()->GetValue(),
+                     const_area->GetLocations()->InAt(0).AsRegister<Register>()));
+      } else {
+        DCHECK(second.IsStackSlot());
+        __ mulss(first.AsFpuRegister<XmmRegister>(), Address(ESP, second.GetStackIndex()));
+      }
       break;
     }
 
     case Primitive::kPrimDouble: {
-      __ mulsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
+      DCHECK(first.Equals(locations->Out()));
+      if (second.IsFpuRegister()) {
+        __ mulsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
+      } else if (mul->InputAt(1)->IsX86LoadFromConstantTable()) {
+        HX86LoadFromConstantTable* const_area = mul->InputAt(1)->AsX86LoadFromConstantTable();
+        DCHECK(!const_area->NeedsMaterialization());
+        __ mulsd(first.AsFpuRegister<XmmRegister>(),
+                 codegen_->LiteralDoubleAddress(
+                     const_area->GetConstant()->AsDoubleConstant()->GetValue(),
+                     const_area->GetLocations()->InAt(0).AsRegister<Register>()));
+      } else {
+        DCHECK(second.IsDoubleStackSlot());
+        __ mulsd(first.AsFpuRegister<XmmRegister>(), Address(ESP, second.GetStackIndex()));
+      }
       break;
     }
 
@@ -2855,7 +2914,7 @@
     case Primitive::kPrimFloat:
     case Primitive::kPrimDouble: {
       locations->SetInAt(0, Location::RequiresFpuRegister());
-      locations->SetInAt(1, Location::RequiresFpuRegister());
+      locations->SetInAt(1, Location::Any());
       locations->SetOut(Location::SameAsFirstInput());
       break;
     }
@@ -2867,7 +2926,6 @@
 
 void InstructionCodeGeneratorX86::VisitDiv(HDiv* div) {
   LocationSummary* locations = div->GetLocations();
-  Location out = locations->Out();
   Location first = locations->InAt(0);
   Location second = locations->InAt(1);
 
@@ -2879,14 +2937,36 @@
     }
 
     case Primitive::kPrimFloat: {
-      DCHECK(first.Equals(out));
-      __ divss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
+      if (second.IsFpuRegister()) {
+        __ divss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
+      } else if (div->InputAt(1)->IsX86LoadFromConstantTable()) {
+        HX86LoadFromConstantTable* const_area = div->InputAt(1)->AsX86LoadFromConstantTable();
+        DCHECK(!const_area->NeedsMaterialization());
+        __ divss(first.AsFpuRegister<XmmRegister>(),
+                 codegen_->LiteralFloatAddress(
+                   const_area->GetConstant()->AsFloatConstant()->GetValue(),
+                   const_area->GetLocations()->InAt(0).AsRegister<Register>()));
+      } else {
+        DCHECK(second.IsStackSlot());
+        __ divss(first.AsFpuRegister<XmmRegister>(), Address(ESP, second.GetStackIndex()));
+      }
       break;
     }
 
     case Primitive::kPrimDouble: {
-      DCHECK(first.Equals(out));
-      __ divsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
+      if (second.IsFpuRegister()) {
+        __ divsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
+      } else if (div->InputAt(1)->IsX86LoadFromConstantTable()) {
+        HX86LoadFromConstantTable* const_area = div->InputAt(1)->AsX86LoadFromConstantTable();
+        DCHECK(!const_area->NeedsMaterialization());
+        __ divsd(first.AsFpuRegister<XmmRegister>(),
+                 codegen_->LiteralDoubleAddress(
+                   const_area->GetConstant()->AsDoubleConstant()->GetValue(),
+                   const_area->GetLocations()->InAt(0).AsRegister<Register>()));
+      } else {
+        DCHECK(second.IsDoubleStackSlot());
+        __ divsd(first.AsFpuRegister<XmmRegister>(), Address(ESP, second.GetStackIndex()));
+      }
       break;
     }
 
@@ -3570,6 +3650,25 @@
   DCHECK(!IsLeafMethod());
 }
 
+void CodeGeneratorX86::GenerateVirtualCall(HInvokeVirtual* invoke, Location temp_in) {
+  Register temp = temp_in.AsRegister<Register>();
+  uint32_t method_offset = mirror::Class::EmbeddedVTableEntryOffset(
+      invoke->GetVTableIndex(), kX86PointerSize).Uint32Value();
+  LocationSummary* locations = invoke->GetLocations();
+  Location receiver = locations->InAt(0);
+  uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
+  // temp = object->GetClass();
+  DCHECK(receiver.IsRegister());
+  __ movl(temp, Address(receiver.AsRegister<Register>(), class_offset));
+  MaybeRecordImplicitNullCheck(invoke);
+  __ MaybeUnpoisonHeapReference(temp);
+  // temp = temp->GetMethodAt(method_offset);
+  __ movl(temp, Address(temp, method_offset));
+  // call temp->GetEntryPoint();
+  __ call(Address(
+      temp, ArtMethod::EntryPointFromQuickCompiledCodeOffset(kX86WordSize).Int32Value()));
+}
+
 void CodeGeneratorX86::EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patches) {
   DCHECK(linker_patches->empty());
   linker_patches->reserve(method_patches_.size() + relative_call_patches_.size());
@@ -5085,6 +5184,245 @@
   // Will be generated at use site.
 }
 
+void LocationsBuilderX86::VisitX86ComputeBaseMethodAddress(
+    HX86ComputeBaseMethodAddress* insn) {
+  LocationSummary* locations =
+      new (GetGraph()->GetArena()) LocationSummary(insn, LocationSummary::kNoCall);
+  locations->SetOut(Location::RequiresRegister());
+}
+
+void InstructionCodeGeneratorX86::VisitX86ComputeBaseMethodAddress(
+    HX86ComputeBaseMethodAddress* insn) {
+  LocationSummary* locations = insn->GetLocations();
+  Register reg = locations->Out().AsRegister<Register>();
+
+  // Generate call to next instruction.
+  Label next_instruction;
+  __ call(&next_instruction);
+  __ Bind(&next_instruction);
+
+  // Remember this offset for later use with constant area.
+  codegen_->SetMethodAddressOffset(GetAssembler()->CodeSize());
+
+  // Grab the return address off the stack.
+  __ popl(reg);
+}
+
+void LocationsBuilderX86::VisitX86LoadFromConstantTable(
+    HX86LoadFromConstantTable* insn) {
+  LocationSummary* locations =
+      new (GetGraph()->GetArena()) LocationSummary(insn, LocationSummary::kNoCall);
+
+  locations->SetInAt(0, Location::RequiresRegister());
+  locations->SetInAt(1, Location::ConstantLocation(insn->GetConstant()));
+
+  // If we don't need to be materialized, we only need the inputs to be set.
+  if (!insn->NeedsMaterialization()) {
+    return;
+  }
+
+  switch (insn->GetType()) {
+    case Primitive::kPrimFloat:
+    case Primitive::kPrimDouble:
+      locations->SetOut(Location::RequiresFpuRegister());
+      break;
+
+    case Primitive::kPrimInt:
+      locations->SetOut(Location::RequiresRegister());
+      break;
+
+    default:
+      LOG(FATAL) << "Unsupported x86 constant area type " << insn->GetType();
+  }
+}
+
+void InstructionCodeGeneratorX86::VisitX86LoadFromConstantTable(HX86LoadFromConstantTable* insn) {
+  if (!insn->NeedsMaterialization()) {
+    return;
+  }
+
+  LocationSummary* locations = insn->GetLocations();
+  Location out = locations->Out();
+  Register const_area = locations->InAt(0).AsRegister<Register>();
+  HConstant *value = insn->GetConstant();
+
+  switch (insn->GetType()) {
+    case Primitive::kPrimFloat:
+      __ movss(out.AsFpuRegister<XmmRegister>(),
+               codegen_->LiteralFloatAddress(value->AsFloatConstant()->GetValue(), const_area));
+      break;
+
+    case Primitive::kPrimDouble:
+      __ movsd(out.AsFpuRegister<XmmRegister>(),
+               codegen_->LiteralDoubleAddress(value->AsDoubleConstant()->GetValue(), const_area));
+      break;
+
+    case Primitive::kPrimInt:
+      __ movl(out.AsRegister<Register>(),
+              codegen_->LiteralInt32Address(value->AsIntConstant()->GetValue(), const_area));
+      break;
+
+    default:
+      LOG(FATAL) << "Unsupported x86 constant area type " << insn->GetType();
+  }
+}
+
+void CodeGeneratorX86::Finalize(CodeAllocator* allocator) {
+  // Generate the constant area if needed.
+  X86Assembler* assembler = GetAssembler();
+  if (!assembler->IsConstantAreaEmpty()) {
+    // Align to 4 byte boundary to reduce cache misses, as the data is 4 and 8
+    // byte values.
+    assembler->Align(4, 0);
+    constant_area_start_ = assembler->CodeSize();
+    assembler->AddConstantArea();
+  }
+
+  // And finish up.
+  CodeGenerator::Finalize(allocator);
+}
+
+/**
+ * Class to handle late fixup of offsets into constant area.
+ */
+class RIPFixup : public AssemblerFixup, public ArenaObject<kArenaAllocMisc> {
+ public:
+  RIPFixup(const CodeGeneratorX86& codegen, int offset)
+      : codegen_(codegen), offset_into_constant_area_(offset) {}
+
+ private:
+  void Process(const MemoryRegion& region, int pos) OVERRIDE {
+    // Patch the correct offset for the instruction.  The place to patch is the
+    // last 4 bytes of the instruction.
+    // The value to patch is the distance from the offset in the constant area
+    // from the address computed by the HX86ComputeBaseMethodAddress instruction.
+    int32_t constant_offset = codegen_.ConstantAreaStart() + offset_into_constant_area_;
+    int32_t relative_position = constant_offset - codegen_.GetMethodAddressOffset();;
+
+    // Patch in the right value.
+    region.StoreUnaligned<int32_t>(pos - 4, relative_position);
+  }
+
+  const CodeGeneratorX86& codegen_;
+
+  // Location in constant area that the fixup refers to.
+  int offset_into_constant_area_;
+};
+
+Address CodeGeneratorX86::LiteralDoubleAddress(double v, Register reg) {
+  AssemblerFixup* fixup = new (GetGraph()->GetArena()) RIPFixup(*this, __ AddDouble(v));
+  return Address(reg, kDummy32BitOffset, fixup);
+}
+
+Address CodeGeneratorX86::LiteralFloatAddress(float v, Register reg) {
+  AssemblerFixup* fixup = new (GetGraph()->GetArena()) RIPFixup(*this, __ AddFloat(v));
+  return Address(reg, kDummy32BitOffset, fixup);
+}
+
+Address CodeGeneratorX86::LiteralInt32Address(int32_t v, Register reg) {
+  AssemblerFixup* fixup = new (GetGraph()->GetArena()) RIPFixup(*this, __ AddInt32(v));
+  return Address(reg, kDummy32BitOffset, fixup);
+}
+
+Address CodeGeneratorX86::LiteralInt64Address(int64_t v, Register reg) {
+  AssemblerFixup* fixup = new (GetGraph()->GetArena()) RIPFixup(*this, __ AddInt64(v));
+  return Address(reg, kDummy32BitOffset, fixup);
+}
+
+/**
+ * Finds instructions that need the constant area base as an input.
+ */
+class ConstantHandlerVisitor : public HGraphVisitor {
+ public:
+  explicit ConstantHandlerVisitor(HGraph* graph) : HGraphVisitor(graph), base_(nullptr) {}
+
+ private:
+  void VisitAdd(HAdd* add) OVERRIDE {
+    BinaryFP(add);
+  }
+
+  void VisitSub(HSub* sub) OVERRIDE {
+    BinaryFP(sub);
+  }
+
+  void VisitMul(HMul* mul) OVERRIDE {
+    BinaryFP(mul);
+  }
+
+  void VisitDiv(HDiv* div) OVERRIDE {
+    BinaryFP(div);
+  }
+
+  void VisitReturn(HReturn* ret) OVERRIDE {
+    HConstant* value = ret->InputAt(0)->AsConstant();
+    if ((value != nullptr && Primitive::IsFloatingPointType(value->GetType()))) {
+      ReplaceInput(ret, value, 0, true);
+    }
+  }
+
+  void VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) OVERRIDE {
+    HandleInvoke(invoke);
+  }
+
+  void VisitInvokeVirtual(HInvokeVirtual* invoke) OVERRIDE {
+    HandleInvoke(invoke);
+  }
+
+  void VisitInvokeInterface(HInvokeInterface* invoke) OVERRIDE {
+    HandleInvoke(invoke);
+  }
+
+  void BinaryFP(HBinaryOperation* bin) {
+    HConstant* rhs = bin->InputAt(1)->AsConstant();
+    if (rhs != nullptr && Primitive::IsFloatingPointType(bin->GetResultType())) {
+      ReplaceInput(bin, rhs, 1, false);
+    }
+  }
+
+  void InitializeConstantAreaPointer(HInstruction* user) {
+    // Ensure we only initialize the pointer once.
+    if (base_ != nullptr) {
+      return;
+    }
+
+    HGraph* graph = GetGraph();
+    HBasicBlock* entry = graph->GetEntryBlock();
+    base_ = new (graph->GetArena()) HX86ComputeBaseMethodAddress();
+    HInstruction* insert_pos = (user->GetBlock() == entry) ? user : entry->GetLastInstruction();
+    entry->InsertInstructionBefore(base_, insert_pos);
+    DCHECK(base_ != nullptr);
+  }
+
+  void ReplaceInput(HInstruction* insn, HConstant* value, int input_index, bool materialize) {
+    InitializeConstantAreaPointer(insn);
+    HGraph* graph = GetGraph();
+    HBasicBlock* block = insn->GetBlock();
+    HX86LoadFromConstantTable* load_constant =
+        new (graph->GetArena()) HX86LoadFromConstantTable(base_, value, materialize);
+    block->InsertInstructionBefore(load_constant, insn);
+    insn->ReplaceInput(load_constant, input_index);
+  }
+
+  void HandleInvoke(HInvoke* invoke) {
+    // Ensure that we can load FP arguments from the constant area.
+    for (size_t i = 0, e = invoke->InputCount(); i < e; i++) {
+      HConstant* input = invoke->InputAt(i)->AsConstant();
+      if (input != nullptr && Primitive::IsFloatingPointType(input->GetType())) {
+        ReplaceInput(invoke, input, i, true);
+      }
+    }
+  }
+
+  // The generated HX86ComputeBaseMethodAddress in the entry block needed as an
+  // input to the HX86LoadFromConstantTable instructions.
+  HX86ComputeBaseMethodAddress* base_;
+};
+
+void ConstantAreaFixups::Run() {
+  ConstantHandlerVisitor visitor(graph_);
+  visitor.VisitInsertionOrder();
+}
+
 #undef __
 
 }  // namespace x86
diff --git a/compiler/optimizing/code_generator_x86.h b/compiler/optimizing/code_generator_x86.h
index 17787a8..bd7cb12 100644
--- a/compiler/optimizing/code_generator_x86.h
+++ b/compiler/optimizing/code_generator_x86.h
@@ -294,6 +294,8 @@
 
   // Generate a call to a static or direct method.
   void GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp);
+  // Generate a call to a virtual method.
+  void GenerateVirtualCall(HInvokeVirtual* invoke, Location temp);
 
   // Emit linker patches.
   void EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patches) OVERRIDE;
@@ -325,6 +327,25 @@
     return isa_features_;
   }
 
+  void SetMethodAddressOffset(int32_t offset) {
+    method_address_offset_ = offset;
+  }
+
+  int32_t GetMethodAddressOffset() const {
+    return method_address_offset_;
+  }
+
+  int32_t ConstantAreaStart() const {
+    return constant_area_start_;
+  }
+
+  Address LiteralDoubleAddress(double v, Register reg);
+  Address LiteralFloatAddress(float v, Register reg);
+  Address LiteralInt32Address(int32_t v, Register reg);
+  Address LiteralInt64Address(int64_t v, Register reg);
+
+  void Finalize(CodeAllocator* allocator) OVERRIDE;
+
  private:
   // Labels for each block that will be compiled.
   GrowableArray<Label> block_labels_;
@@ -339,6 +360,20 @@
   ArenaDeque<MethodPatchInfo<Label>> method_patches_;
   ArenaDeque<MethodPatchInfo<Label>> relative_call_patches_;
 
+  // Offset to the start of the constant area in the assembled code.
+  // Used for fixups to the constant area.
+  int32_t constant_area_start_;
+
+  // If there is a HX86ComputeBaseMethodAddress instruction in the graph
+  // (which shall be the sole instruction of this kind), subtracting this offset
+  // from the value contained in the out register of this HX86ComputeBaseMethodAddress
+  // instruction gives the address of the start of this method.
+  int32_t method_address_offset_;
+
+  // When we don't know the proper offset for the value, we use kDummy32BitOffset.
+  // The correct value will be inserted when processing Assembler fixups.
+  static constexpr int32_t kDummy32BitOffset = 256;
+
   DISALLOW_COPY_AND_ASSIGN(CodeGeneratorX86);
 };
 
diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc
index e1ec2ea..0f3eb74 100644
--- a/compiler/optimizing/code_generator_x86_64.cc
+++ b/compiler/optimizing/code_generator_x86_64.cc
@@ -475,6 +475,25 @@
   DCHECK(!IsLeafMethod());
 }
 
+void CodeGeneratorX86_64::GenerateVirtualCall(HInvokeVirtual* invoke, Location temp_in) {
+  CpuRegister temp = temp_in.AsRegister<CpuRegister>();
+  size_t method_offset = mirror::Class::EmbeddedVTableEntryOffset(
+      invoke->GetVTableIndex(), kX86_64PointerSize).SizeValue();
+  LocationSummary* locations = invoke->GetLocations();
+  Location receiver = locations->InAt(0);
+  size_t class_offset = mirror::Object::ClassOffset().SizeValue();
+  // temp = object->GetClass();
+  DCHECK(receiver.IsRegister());
+  __ movl(temp, Address(receiver.AsRegister<CpuRegister>(), class_offset));
+  MaybeRecordImplicitNullCheck(invoke);
+  __ MaybeUnpoisonHeapReference(temp);
+  // temp = temp->GetMethodAt(method_offset);
+  __ movq(temp, Address(temp, method_offset));
+  // call temp->GetEntryPoint();
+  __ call(Address(temp, ArtMethod::EntryPointFromQuickCompiledCodeOffset(
+      kX86_64WordSize).SizeValue()));
+}
+
 void CodeGeneratorX86_64::EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patches) {
   DCHECK(linker_patches->empty());
   size_t size =
@@ -1709,22 +1728,7 @@
     return;
   }
 
-  CpuRegister temp = invoke->GetLocations()->GetTemp(0).AsRegister<CpuRegister>();
-  size_t method_offset = mirror::Class::EmbeddedVTableEntryOffset(
-      invoke->GetVTableIndex(), kX86_64PointerSize).SizeValue();
-  LocationSummary* locations = invoke->GetLocations();
-  Location receiver = locations->InAt(0);
-  size_t class_offset = mirror::Object::ClassOffset().SizeValue();
-  // temp = object->GetClass();
-  DCHECK(receiver.IsRegister());
-  __ movl(temp, Address(receiver.AsRegister<CpuRegister>(), class_offset));
-  codegen_->MaybeRecordImplicitNullCheck(invoke);
-  __ MaybeUnpoisonHeapReference(temp);
-  // temp = temp->GetMethodAt(method_offset);
-  __ movq(temp, Address(temp, method_offset));
-  // call temp->GetEntryPoint();
-  __ call(Address(temp, ArtMethod::EntryPointFromQuickCompiledCodeOffset(
-      kX86_64WordSize).SizeValue()));
+  codegen_->GenerateVirtualCall(invoke, invoke->GetLocations()->GetTemp(0));
 
   DCHECK(!codegen_->IsLeafMethod());
   codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
diff --git a/compiler/optimizing/code_generator_x86_64.h b/compiler/optimizing/code_generator_x86_64.h
index 21357be..f9d8e04 100644
--- a/compiler/optimizing/code_generator_x86_64.h
+++ b/compiler/optimizing/code_generator_x86_64.h
@@ -305,6 +305,7 @@
   }
 
   void GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp);
+  void GenerateVirtualCall(HInvokeVirtual* invoke, Location temp);
 
   void EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patches) OVERRIDE;
 
diff --git a/compiler/optimizing/constant_area_fixups_x86.h b/compiler/optimizing/constant_area_fixups_x86.h
new file mode 100644
index 0000000..4138039
--- /dev/null
+++ b/compiler/optimizing/constant_area_fixups_x86.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_COMPILER_OPTIMIZING_CONSTANT_AREA_FIXUPS_X86_H_
+#define ART_COMPILER_OPTIMIZING_CONSTANT_AREA_FIXUPS_X86_H_
+
+#include "nodes.h"
+#include "optimization.h"
+
+namespace art {
+namespace x86 {
+
+class ConstantAreaFixups : public HOptimization {
+ public:
+  ConstantAreaFixups(HGraph* graph, OptimizingCompilerStats* stats)
+      : HOptimization(graph, "constant_area_fixups_x86", stats) {}
+
+  void Run() OVERRIDE;
+};
+
+}  // namespace x86
+}  // namespace art
+
+#endif  // ART_COMPILER_OPTIMIZING_CONSTANT_AREA_FIXUPS_X86_H_
diff --git a/compiler/optimizing/intrinsics.cc b/compiler/optimizing/intrinsics.cc
index 075ec1e..41c239d 100644
--- a/compiler/optimizing/intrinsics.cc
+++ b/compiler/optimizing/intrinsics.cc
@@ -16,12 +16,17 @@
 
 #include "intrinsics.h"
 
+#include "art_method.h"
+#include "class_linker.h"
 #include "dex/quick/dex_file_method_inliner.h"
 #include "dex/quick/dex_file_to_method_inliner_map.h"
 #include "driver/compiler_driver.h"
 #include "invoke_type.h"
+#include "mirror/dex_cache-inl.h"
 #include "nodes.h"
 #include "quick/inline_method_analyser.h"
+#include "scoped_thread_state_change.h"
+#include "thread-inl.h"
 #include "utils.h"
 
 namespace art {
@@ -328,14 +333,23 @@
   return Intrinsics::kNone;
 }
 
-static bool CheckInvokeType(Intrinsics intrinsic, HInvoke* invoke) {
+static bool CheckInvokeType(Intrinsics intrinsic, HInvoke* invoke, const DexFile& dex_file) {
   // The DexFileMethodInliner should have checked whether the methods are agreeing with
   // what we expect, i.e., static methods are called as such. Add another check here for
   // our expectations:
-  // Whenever the intrinsic is marked as static-or-direct, report an error if we find an
-  // InvokeVirtual. The other direction is not possible: we have intrinsics for virtual
-  // functions that will perform a check inline. If the precise type is known, however,
-  // the instruction will be sharpened to an InvokeStaticOrDirect.
+  //
+  // Whenever the intrinsic is marked as static, report an error if we find an InvokeVirtual.
+  //
+  // Whenever the intrinsic is marked as direct and we find an InvokeVirtual, a devirtualization
+  // failure occured. We might be in a situation where we have inlined a method that calls an
+  // intrinsic, but that method is in a different dex file on which we do not have a
+  // verified_method that would have helped the compiler driver sharpen the call. In that case,
+  // make sure that the intrinsic is actually for some final method (or in a final class), as
+  // otherwise the intrinsics setup is broken.
+  //
+  // For the last direction, we have intrinsics for virtual functions that will perform a check
+  // inline. If the precise type is known, however, the instruction will be sharpened to an
+  // InvokeStaticOrDirect.
   InvokeType intrinsic_type = GetIntrinsicInvokeType(intrinsic);
   InvokeType invoke_type = invoke->IsInvokeStaticOrDirect() ?
       invoke->AsInvokeStaticOrDirect()->GetInvokeType() :
@@ -343,8 +357,22 @@
   switch (intrinsic_type) {
     case kStatic:
       return (invoke_type == kStatic);
+
     case kDirect:
-      return (invoke_type == kDirect);
+      if (invoke_type == kDirect) {
+        return true;
+      }
+      if (invoke_type == kVirtual) {
+        ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+        ScopedObjectAccess soa(Thread::Current());
+        ArtMethod* art_method =
+            class_linker->FindDexCache(soa.Self(), dex_file)->GetResolvedMethod(
+                invoke->GetDexMethodIndex(), class_linker->GetImagePointerSize());
+        return art_method != nullptr &&
+            (art_method->IsFinal() || art_method->GetDeclaringClass()->IsFinal());
+      }
+      return false;
+
     case kVirtual:
       // Call might be devirtualized.
       return (invoke_type == kVirtual || invoke_type == kDirect);
@@ -364,17 +392,18 @@
       if (inst->IsInvoke()) {
         HInvoke* invoke = inst->AsInvoke();
         InlineMethod method;
-        DexFileMethodInliner* inliner =
-            driver_->GetMethodInlinerMap()->GetMethodInliner(&invoke->GetDexFile());
+        const DexFile& dex_file = invoke->GetDexFile();
+        DexFileMethodInliner* inliner = driver_->GetMethodInlinerMap()->GetMethodInliner(&dex_file);
         DCHECK(inliner != nullptr);
         if (inliner->IsIntrinsic(invoke->GetDexMethodIndex(), &method)) {
           Intrinsics intrinsic = GetIntrinsic(method, graph_->GetInstructionSet());
 
           if (intrinsic != Intrinsics::kNone) {
-            if (!CheckInvokeType(intrinsic, invoke)) {
+            if (!CheckInvokeType(intrinsic, invoke, dex_file)) {
               LOG(WARNING) << "Found an intrinsic with unexpected invoke type: "
-                           << intrinsic << " for "
-                           << PrettyMethod(invoke->GetDexMethodIndex(), invoke->GetDexFile());
+                  << intrinsic << " for "
+                  << PrettyMethod(invoke->GetDexMethodIndex(), invoke->GetDexFile())
+                  << invoke->DebugName();
             } else {
               invoke->SetIntrinsic(intrinsic, NeedsEnvironmentOrCache(intrinsic));
             }
diff --git a/compiler/optimizing/intrinsics_arm.cc b/compiler/optimizing/intrinsics_arm.cc
index 69a3e62..6040a40 100644
--- a/compiler/optimizing/intrinsics_arm.cc
+++ b/compiler/optimizing/intrinsics_arm.cc
@@ -103,11 +103,11 @@
     if (invoke_->IsInvokeStaticOrDirect()) {
       codegen->GenerateStaticOrDirectCall(invoke_->AsInvokeStaticOrDirect(),
                                           Location::RegisterLocation(kArtMethodRegister));
-      codegen->RecordPcInfo(invoke_, invoke_->GetDexPc(), this);
     } else {
-      UNIMPLEMENTED(FATAL) << "Non-direct intrinsic slow-path not yet implemented";
-      UNREACHABLE();
+      codegen->GenerateVirtualCall(invoke_->AsInvokeVirtual(),
+                                   Location::RegisterLocation(kArtMethodRegister));
     }
+    codegen->RecordPcInfo(invoke_, invoke_->GetDexPc(), this);
 
     // Copy the result back to the expected output.
     Location out = invoke_->GetLocations()->Out();
diff --git a/compiler/optimizing/intrinsics_arm64.cc b/compiler/optimizing/intrinsics_arm64.cc
index 0171d69..1dbca34 100644
--- a/compiler/optimizing/intrinsics_arm64.cc
+++ b/compiler/optimizing/intrinsics_arm64.cc
@@ -112,11 +112,10 @@
     if (invoke_->IsInvokeStaticOrDirect()) {
       codegen->GenerateStaticOrDirectCall(invoke_->AsInvokeStaticOrDirect(),
                                           LocationFrom(kArtMethodRegister));
-      codegen->RecordPcInfo(invoke_, invoke_->GetDexPc(), this);
     } else {
-      UNIMPLEMENTED(FATAL) << "Non-direct intrinsic slow-path not yet implemented";
-      UNREACHABLE();
+      codegen->GenerateVirtualCall(invoke_->AsInvokeVirtual(), LocationFrom(kArtMethodRegister));
     }
+    codegen->RecordPcInfo(invoke_, invoke_->GetDexPc(), this);
 
     // Copy the result back to the expected output.
     Location out = invoke_->GetLocations()->Out();
diff --git a/compiler/optimizing/intrinsics_x86.cc b/compiler/optimizing/intrinsics_x86.cc
index be076cd..daf56d0 100644
--- a/compiler/optimizing/intrinsics_x86.cc
+++ b/compiler/optimizing/intrinsics_x86.cc
@@ -141,11 +141,10 @@
     if (invoke_->IsInvokeStaticOrDirect()) {
       codegen->GenerateStaticOrDirectCall(invoke_->AsInvokeStaticOrDirect(),
                                           Location::RegisterLocation(EAX));
-      codegen->RecordPcInfo(invoke_, invoke_->GetDexPc(), this);
     } else {
-      UNIMPLEMENTED(FATAL) << "Non-direct intrinsic slow-path not yet implemented";
-      UNREACHABLE();
+      codegen->GenerateVirtualCall(invoke_->AsInvokeVirtual(), Location::RegisterLocation(EAX));
     }
+    codegen->RecordPcInfo(invoke_, invoke_->GetDexPc(), this);
 
     // Copy the result back to the expected output.
     Location out = invoke_->GetLocations()->Out();
diff --git a/compiler/optimizing/intrinsics_x86_64.cc b/compiler/optimizing/intrinsics_x86_64.cc
index 1f35b59..f78a726 100644
--- a/compiler/optimizing/intrinsics_x86_64.cc
+++ b/compiler/optimizing/intrinsics_x86_64.cc
@@ -132,11 +132,10 @@
     if (invoke_->IsInvokeStaticOrDirect()) {
       codegen->GenerateStaticOrDirectCall(
           invoke_->AsInvokeStaticOrDirect(), Location::RegisterLocation(RDI));
-      codegen->RecordPcInfo(invoke_, invoke_->GetDexPc(), this);
     } else {
-      UNIMPLEMENTED(FATAL) << "Non-direct intrinsic slow-path not yet implemented";
-      UNREACHABLE();
+      codegen->GenerateVirtualCall(invoke_->AsInvokeVirtual(), Location::RegisterLocation(RDI));
     }
+    codegen->RecordPcInfo(invoke_, invoke_->GetDexPc(), this);
 
     // Copy the result back to the expected output.
     Location out = invoke_->GetLocations()->Out();
diff --git a/compiler/optimizing/nodes.cc b/compiler/optimizing/nodes.cc
index 4332d7e..650c8e5 100644
--- a/compiler/optimizing/nodes.cc
+++ b/compiler/optimizing/nodes.cc
@@ -207,7 +207,7 @@
   // Insert a new node between `block` and `successor` to split the
   // critical edge.
   HBasicBlock* new_block = SplitEdge(block, successor);
-  new_block->AddInstruction(new (arena_) HGoto());
+  new_block->AddInstruction(new (arena_) HGoto(successor->GetDexPc()));
   if (successor->IsLoopHeader()) {
     // If we split at a back edge boundary, make the new block the back edge.
     HLoopInformation* info = successor->GetLoopInformation();
@@ -228,7 +228,7 @@
   if (number_of_incomings != 1) {
     HBasicBlock* pre_header = new (arena_) HBasicBlock(this, header->GetDexPc());
     AddBlock(pre_header);
-    pre_header->AddInstruction(new (arena_) HGoto());
+    pre_header->AddInstruction(new (arena_) HGoto(header->GetDexPc()));
 
     for (size_t pred = 0; pred < header->GetPredecessors().Size(); ++pred) {
       HBasicBlock* predecessor = header->GetPredecessors().Get(pred);
@@ -409,12 +409,12 @@
   }
 }
 
-HNullConstant* HGraph::GetNullConstant() {
+HNullConstant* HGraph::GetNullConstant(uint32_t dex_pc) {
   // For simplicity, don't bother reviving the cached null constant if it is
   // not null and not in a block. Otherwise, we need to clear the instruction
   // id and/or any invariants the graph is assuming when adding new instructions.
   if ((cached_null_constant_ == nullptr) || (cached_null_constant_->GetBlock() == nullptr)) {
-    cached_null_constant_ = new (arena_) HNullConstant();
+    cached_null_constant_ = new (arena_) HNullConstant(dex_pc);
     InsertConstant(cached_null_constant_);
   }
   return cached_null_constant_;
@@ -426,7 +426,8 @@
   // id and/or any invariants the graph is assuming when adding new instructions.
   if ((cached_current_method_ == nullptr) || (cached_current_method_->GetBlock() == nullptr)) {
     cached_current_method_ = new (arena_) HCurrentMethod(
-        Is64BitInstructionSet(instruction_set_) ? Primitive::kPrimLong : Primitive::kPrimInt);
+        Is64BitInstructionSet(instruction_set_) ? Primitive::kPrimLong : Primitive::kPrimInt,
+        entry_block_->GetDexPc());
     if (entry_block_->GetFirstInstruction() == nullptr) {
       entry_block_->AddInstruction(cached_current_method_);
     } else {
@@ -437,7 +438,7 @@
   return cached_current_method_;
 }
 
-HConstant* HGraph::GetConstant(Primitive::Type type, int64_t value) {
+HConstant* HGraph::GetConstant(Primitive::Type type, int64_t value, uint32_t dex_pc) {
   switch (type) {
     case Primitive::Type::kPrimBoolean:
       DCHECK(IsUint<1>(value));
@@ -447,10 +448,10 @@
     case Primitive::Type::kPrimShort:
     case Primitive::Type::kPrimInt:
       DCHECK(IsInt(Primitive::ComponentSize(type) * kBitsPerByte, value));
-      return GetIntConstant(static_cast<int32_t>(value));
+      return GetIntConstant(static_cast<int32_t>(value), dex_pc);
 
     case Primitive::Type::kPrimLong:
-      return GetLongConstant(value);
+      return GetLongConstant(value, dex_pc);
 
     default:
       LOG(FATAL) << "Unsupported constant type";
@@ -944,11 +945,11 @@
     int32_t value = GetInput()->AsIntConstant()->GetValue();
     switch (GetResultType()) {
       case Primitive::kPrimLong:
-        return graph->GetLongConstant(static_cast<int64_t>(value));
+        return graph->GetLongConstant(static_cast<int64_t>(value), GetDexPc());
       case Primitive::kPrimFloat:
-        return graph->GetFloatConstant(static_cast<float>(value));
+        return graph->GetFloatConstant(static_cast<float>(value), GetDexPc());
       case Primitive::kPrimDouble:
-        return graph->GetDoubleConstant(static_cast<double>(value));
+        return graph->GetDoubleConstant(static_cast<double>(value), GetDexPc());
       default:
         return nullptr;
     }
@@ -956,11 +957,11 @@
     int64_t value = GetInput()->AsLongConstant()->GetValue();
     switch (GetResultType()) {
       case Primitive::kPrimInt:
-        return graph->GetIntConstant(static_cast<int32_t>(value));
+        return graph->GetIntConstant(static_cast<int32_t>(value), GetDexPc());
       case Primitive::kPrimFloat:
-        return graph->GetFloatConstant(static_cast<float>(value));
+        return graph->GetFloatConstant(static_cast<float>(value), GetDexPc());
       case Primitive::kPrimDouble:
-        return graph->GetDoubleConstant(static_cast<double>(value));
+        return graph->GetDoubleConstant(static_cast<double>(value), GetDexPc());
       default:
         return nullptr;
     }
@@ -969,22 +970,22 @@
     switch (GetResultType()) {
       case Primitive::kPrimInt:
         if (std::isnan(value))
-          return graph->GetIntConstant(0);
+          return graph->GetIntConstant(0, GetDexPc());
         if (value >= kPrimIntMax)
-          return graph->GetIntConstant(kPrimIntMax);
+          return graph->GetIntConstant(kPrimIntMax, GetDexPc());
         if (value <= kPrimIntMin)
-          return graph->GetIntConstant(kPrimIntMin);
-        return graph->GetIntConstant(static_cast<int32_t>(value));
+          return graph->GetIntConstant(kPrimIntMin, GetDexPc());
+        return graph->GetIntConstant(static_cast<int32_t>(value), GetDexPc());
       case Primitive::kPrimLong:
         if (std::isnan(value))
-          return graph->GetLongConstant(0);
+          return graph->GetLongConstant(0, GetDexPc());
         if (value >= kPrimLongMax)
-          return graph->GetLongConstant(kPrimLongMax);
+          return graph->GetLongConstant(kPrimLongMax, GetDexPc());
         if (value <= kPrimLongMin)
-          return graph->GetLongConstant(kPrimLongMin);
-        return graph->GetLongConstant(static_cast<int64_t>(value));
+          return graph->GetLongConstant(kPrimLongMin, GetDexPc());
+        return graph->GetLongConstant(static_cast<int64_t>(value), GetDexPc());
       case Primitive::kPrimDouble:
-        return graph->GetDoubleConstant(static_cast<double>(value));
+        return graph->GetDoubleConstant(static_cast<double>(value), GetDexPc());
       default:
         return nullptr;
     }
@@ -993,22 +994,22 @@
     switch (GetResultType()) {
       case Primitive::kPrimInt:
         if (std::isnan(value))
-          return graph->GetIntConstant(0);
+          return graph->GetIntConstant(0, GetDexPc());
         if (value >= kPrimIntMax)
-          return graph->GetIntConstant(kPrimIntMax);
+          return graph->GetIntConstant(kPrimIntMax, GetDexPc());
         if (value <= kPrimLongMin)
-          return graph->GetIntConstant(kPrimIntMin);
-        return graph->GetIntConstant(static_cast<int32_t>(value));
+          return graph->GetIntConstant(kPrimIntMin, GetDexPc());
+        return graph->GetIntConstant(static_cast<int32_t>(value), GetDexPc());
       case Primitive::kPrimLong:
         if (std::isnan(value))
-          return graph->GetLongConstant(0);
+          return graph->GetLongConstant(0, GetDexPc());
         if (value >= kPrimLongMax)
-          return graph->GetLongConstant(kPrimLongMax);
+          return graph->GetLongConstant(kPrimLongMax, GetDexPc());
         if (value <= kPrimLongMin)
-          return graph->GetLongConstant(kPrimLongMin);
-        return graph->GetLongConstant(static_cast<int64_t>(value));
+          return graph->GetLongConstant(kPrimLongMin, GetDexPc());
+        return graph->GetLongConstant(static_cast<int64_t>(value), GetDexPc());
       case Primitive::kPrimFloat:
-        return graph->GetFloatConstant(static_cast<float>(value));
+        return graph->GetFloatConstant(static_cast<float>(value), GetDexPc());
       default:
         return nullptr;
     }
@@ -1122,7 +1123,8 @@
   DCHECK(!graph_->IsInSsaForm()) << "Support for SSA form not implemented";
   DCHECK_EQ(cursor->GetBlock(), this);
 
-  HBasicBlock* new_block = new (GetGraph()->GetArena()) HBasicBlock(GetGraph(), GetDexPc());
+  HBasicBlock* new_block = new (GetGraph()->GetArena()) HBasicBlock(GetGraph(),
+                                                                    cursor->GetDexPc());
   new_block->instructions_.first_instruction_ = cursor;
   new_block->instructions_.last_instruction_ = instructions_.last_instruction_;
   instructions_.last_instruction_ = cursor->previous_;
@@ -1134,7 +1136,7 @@
   }
 
   new_block->instructions_.SetBlockOfInstructions(new_block);
-  AddInstruction(new (GetGraph()->GetArena()) HGoto());
+  AddInstruction(new (GetGraph()->GetArena()) HGoto(new_block->GetDexPc()));
 
   for (size_t i = 0, e = GetSuccessors().Size(); i < e; ++i) {
     HBasicBlock* successor = GetSuccessors().Get(i);
@@ -1309,7 +1311,7 @@
     predecessor->RemoveSuccessor(this);
     if (predecessor->GetSuccessors().Size() == 1u) {
       DCHECK(last_instruction->IsIf());
-      predecessor->AddInstruction(new (graph_->GetArena()) HGoto());
+      predecessor->AddInstruction(new (graph_->GetArena()) HGoto(last_instruction->GetDexPc()));
     } else {
       // The predecessor has no remaining successors and therefore must be dead.
       // We deliberately leave it without a control-flow instruction so that the
@@ -1562,13 +1564,13 @@
       if (!returns_void) {
         return_value = last->InputAt(0);
       }
-      predecessor->AddInstruction(new (allocator) HGoto());
+      predecessor->AddInstruction(new (allocator) HGoto(last->GetDexPc()));
       predecessor->RemoveInstruction(last);
     } else {
       if (!returns_void) {
         // There will be multiple returns.
         return_value = new (allocator) HPhi(
-            allocator, kNoRegNumber, 0, HPhi::ToPhiType(invoke->GetType()));
+            allocator, kNoRegNumber, 0, HPhi::ToPhiType(invoke->GetType()), to->GetDexPc());
         to->AddPhi(return_value->AsPhi());
       }
       for (size_t i = 0, e = to->GetPredecessors().Size(); i < e; ++i) {
@@ -1577,7 +1579,7 @@
         if (!returns_void) {
           return_value->AsPhi()->AddInput(last->InputAt(0));
         }
-        predecessor->AddInstruction(new (allocator) HGoto());
+        predecessor->AddInstruction(new (allocator) HGoto(last->GetDexPc()));
         predecessor->RemoveInstruction(last);
       }
     }
@@ -1659,15 +1661,19 @@
   for (HInstructionIterator it(entry_block_->GetInstructions()); !it.Done(); it.Advance()) {
     HInstruction* current = it.Current();
     if (current->IsNullConstant()) {
-      current->ReplaceWith(outer_graph->GetNullConstant());
+      current->ReplaceWith(outer_graph->GetNullConstant(current->GetDexPc()));
     } else if (current->IsIntConstant()) {
-      current->ReplaceWith(outer_graph->GetIntConstant(current->AsIntConstant()->GetValue()));
+      current->ReplaceWith(outer_graph->GetIntConstant(
+          current->AsIntConstant()->GetValue(), current->GetDexPc()));
     } else if (current->IsLongConstant()) {
-      current->ReplaceWith(outer_graph->GetLongConstant(current->AsLongConstant()->GetValue()));
+      current->ReplaceWith(outer_graph->GetLongConstant(
+          current->AsLongConstant()->GetValue(), current->GetDexPc()));
     } else if (current->IsFloatConstant()) {
-      current->ReplaceWith(outer_graph->GetFloatConstant(current->AsFloatConstant()->GetValue()));
+      current->ReplaceWith(outer_graph->GetFloatConstant(
+          current->AsFloatConstant()->GetValue(), current->GetDexPc()));
     } else if (current->IsDoubleConstant()) {
-      current->ReplaceWith(outer_graph->GetDoubleConstant(current->AsDoubleConstant()->GetValue()));
+      current->ReplaceWith(outer_graph->GetDoubleConstant(
+          current->AsDoubleConstant()->GetValue(), current->GetDexPc()));
     } else if (current->IsParameterValue()) {
       if (kIsDebugBuild
           && invoke->IsInvokeStaticOrDirect()
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index fef6f21..23d605b 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -77,6 +77,8 @@
 
 static constexpr InvokeType kInvalidInvokeType = static_cast<InvokeType>(-1);
 
+static constexpr uint32_t kNoDexPc = -1;
+
 enum IfCondition {
   kCondEQ,
   kCondNE,
@@ -316,24 +318,24 @@
   // Returns a constant of the given type and value. If it does not exist
   // already, it is created and inserted into the graph. This method is only for
   // integral types.
-  HConstant* GetConstant(Primitive::Type type, int64_t value);
+  HConstant* GetConstant(Primitive::Type type, int64_t value, uint32_t dex_pc = kNoDexPc);
 
   // TODO: This is problematic for the consistency of reference type propagation
   // because it can be created anytime after the pass and thus it will be left
   // with an invalid type.
-  HNullConstant* GetNullConstant();
+  HNullConstant* GetNullConstant(uint32_t dex_pc = kNoDexPc);
 
-  HIntConstant* GetIntConstant(int32_t value) {
-    return CreateConstant(value, &cached_int_constants_);
+  HIntConstant* GetIntConstant(int32_t value, uint32_t dex_pc = kNoDexPc) {
+    return CreateConstant(value, &cached_int_constants_, dex_pc);
   }
-  HLongConstant* GetLongConstant(int64_t value) {
-    return CreateConstant(value, &cached_long_constants_);
+  HLongConstant* GetLongConstant(int64_t value, uint32_t dex_pc = kNoDexPc) {
+    return CreateConstant(value, &cached_long_constants_, dex_pc);
   }
-  HFloatConstant* GetFloatConstant(float value) {
-    return CreateConstant(bit_cast<int32_t, float>(value), &cached_float_constants_);
+  HFloatConstant* GetFloatConstant(float value, uint32_t dex_pc = kNoDexPc) {
+    return CreateConstant(bit_cast<int32_t, float>(value), &cached_float_constants_, dex_pc);
   }
-  HDoubleConstant* GetDoubleConstant(double value) {
-    return CreateConstant(bit_cast<int64_t, double>(value), &cached_double_constants_);
+  HDoubleConstant* GetDoubleConstant(double value, uint32_t dex_pc = kNoDexPc) {
+    return CreateConstant(bit_cast<int64_t, double>(value), &cached_double_constants_, dex_pc);
   }
 
   HCurrentMethod* GetCurrentMethod();
@@ -372,7 +374,8 @@
 
   template <class InstructionType, typename ValueType>
   InstructionType* CreateConstant(ValueType value,
-                                  ArenaSafeMap<ValueType, InstructionType*>* cache) {
+                                  ArenaSafeMap<ValueType, InstructionType*>* cache,
+                                  uint32_t dex_pc = kNoDexPc) {
     // Try to find an existing constant of the given value.
     InstructionType* constant = nullptr;
     auto cached_constant = cache->find(value);
@@ -383,7 +386,7 @@
     // If not found or previously deleted, create and cache a new instruction.
     // Don't bother reviving a previously deleted instruction, for simplicity.
     if (constant == nullptr || constant->GetBlock() == nullptr) {
-      constant = new (arena_) InstructionType(value);
+      constant = new (arena_) InstructionType(value, dex_pc);
       cache->Overwrite(value, constant);
       InsertConstant(constant);
     }
@@ -618,7 +621,6 @@
 };
 
 static constexpr size_t kNoLifetime = -1;
-static constexpr uint32_t kNoDexPc = -1;
 
 // A block in a method. Contains the list of instructions represented
 // as a double linked list. Each block knows its predecessors and
@@ -626,7 +628,7 @@
 
 class HBasicBlock : public ArenaObject<kArenaAllocBasicBlock> {
  public:
-  explicit HBasicBlock(HGraph* graph, uint32_t dex_pc = kNoDexPc)
+  HBasicBlock(HGraph* graph, uint32_t dex_pc = kNoDexPc)
       : graph_(graph),
         predecessors_(graph->GetArena(), kDefaultNumberOfPredecessors),
         successors_(graph->GetArena(), kDefaultNumberOfSuccessors),
@@ -683,6 +685,7 @@
 
   int GetBlockId() const { return block_id_; }
   void SetBlockId(int id) { block_id_ = id; }
+  uint32_t GetDexPc() const { return dex_pc_; }
 
   HBasicBlock* GetDominator() const { return dominator_; }
   void SetDominator(HBasicBlock* dominator) { dominator_ = dominator; }
@@ -943,7 +946,6 @@
   void SetLifetimeStart(size_t start) { lifetime_start_ = start; }
   void SetLifetimeEnd(size_t end) { lifetime_end_ = end; }
 
-  uint32_t GetDexPc() const { return dex_pc_; }
 
   bool EndsWithControlFlowInstruction() const;
   bool EndsWithIf() const;
@@ -1076,7 +1078,9 @@
 
 #define FOR_EACH_CONCRETE_INSTRUCTION_MIPS64(M)
 
-#define FOR_EACH_CONCRETE_INSTRUCTION_X86(M)
+#define FOR_EACH_CONCRETE_INSTRUCTION_X86(M)                            \
+  M(X86ComputeBaseMethodAddress, Instruction)                           \
+  M(X86LoadFromConstantTable, Instruction)
 
 #define FOR_EACH_CONCRETE_INSTRUCTION_X86_64(M)
 
@@ -1689,10 +1693,11 @@
 
 class HInstruction : public ArenaObject<kArenaAllocInstruction> {
  public:
-  explicit HInstruction(SideEffects side_effects)
+  HInstruction(SideEffects side_effects, uint32_t dex_pc = kNoDexPc)
       : previous_(nullptr),
         next_(nullptr),
         block_(nullptr),
+        dex_pc_(dex_pc),
         id_(-1),
         ssa_index_(-1),
         environment_(nullptr),
@@ -1735,9 +1740,9 @@
   }
 
   virtual bool NeedsEnvironment() const { return false; }
-  virtual uint32_t GetDexPc() const {
-    return kNoDexPc;
-  }
+
+  uint32_t GetDexPc() const { return dex_pc_; }
+
   virtual bool IsControlFlow() const { return false; }
 
   virtual bool CanThrow() const { return false; }
@@ -1940,6 +1945,7 @@
   HInstruction* previous_;
   HInstruction* next_;
   HBasicBlock* block_;
+  const uint32_t dex_pc_;
 
   // An instruction gets an id when it is added to the graph.
   // It reflects creation order. A negative id means the instruction
@@ -2044,8 +2050,8 @@
 template<size_t N>
 class HTemplateInstruction: public HInstruction {
  public:
-  HTemplateInstruction<N>(SideEffects side_effects)
-      : HInstruction(side_effects), inputs_() {}
+  HTemplateInstruction<N>(SideEffects side_effects, uint32_t dex_pc = kNoDexPc)
+      : HInstruction(side_effects, dex_pc), inputs_() {}
   virtual ~HTemplateInstruction() {}
 
   size_t InputCount() const OVERRIDE { return N; }
@@ -2071,7 +2077,9 @@
 template<>
 class HTemplateInstruction<0>: public HInstruction {
  public:
-  explicit HTemplateInstruction(SideEffects side_effects) : HInstruction(side_effects) {}
+  explicit HTemplateInstruction<0>(SideEffects side_effects, uint32_t dex_pc = kNoDexPc)
+      : HInstruction(side_effects, dex_pc) {}
+
   virtual ~HTemplateInstruction() {}
 
   size_t InputCount() const OVERRIDE { return 0; }
@@ -2095,8 +2103,8 @@
 template<intptr_t N>
 class HExpression : public HTemplateInstruction<N> {
  public:
-  HExpression<N>(Primitive::Type type, SideEffects side_effects)
-      : HTemplateInstruction<N>(side_effects), type_(type) {}
+  HExpression<N>(Primitive::Type type, SideEffects side_effects, uint32_t dex_pc = kNoDexPc)
+      : HTemplateInstruction<N>(side_effects, dex_pc), type_(type) {}
   virtual ~HExpression() {}
 
   Primitive::Type GetType() const OVERRIDE { return type_; }
@@ -2109,7 +2117,8 @@
 // instruction that branches to the exit block.
 class HReturnVoid : public HTemplateInstruction<0> {
  public:
-  HReturnVoid() : HTemplateInstruction(SideEffects::None()) {}
+  explicit HReturnVoid(uint32_t dex_pc = kNoDexPc)
+      : HTemplateInstruction(SideEffects::None(), dex_pc) {}
 
   bool IsControlFlow() const OVERRIDE { return true; }
 
@@ -2123,7 +2132,8 @@
 // instruction that branches to the exit block.
 class HReturn : public HTemplateInstruction<1> {
  public:
-  explicit HReturn(HInstruction* value) : HTemplateInstruction(SideEffects::None()) {
+  explicit HReturn(HInstruction* value, uint32_t dex_pc = kNoDexPc)
+      : HTemplateInstruction(SideEffects::None(), dex_pc) {
     SetRawInputAt(0, value);
   }
 
@@ -2140,7 +2150,7 @@
 // exit block.
 class HExit : public HTemplateInstruction<0> {
  public:
-  HExit() : HTemplateInstruction(SideEffects::None()) {}
+  explicit HExit(uint32_t dex_pc = kNoDexPc) : HTemplateInstruction(SideEffects::None(), dex_pc) {}
 
   bool IsControlFlow() const OVERRIDE { return true; }
 
@@ -2153,7 +2163,7 @@
 // Jumps from one block to another.
 class HGoto : public HTemplateInstruction<0> {
  public:
-  HGoto() : HTemplateInstruction(SideEffects::None()) {}
+  explicit HGoto(uint32_t dex_pc = kNoDexPc) : HTemplateInstruction(SideEffects::None(), dex_pc) {}
 
   bool IsControlFlow() const OVERRIDE { return true; }
 
@@ -2169,7 +2179,8 @@
 
 class HConstant : public HExpression<0> {
  public:
-  explicit HConstant(Primitive::Type type) : HExpression(type, SideEffects::None()) {}
+  explicit HConstant(Primitive::Type type, uint32_t dex_pc = kNoDexPc)
+      : HExpression(type, SideEffects::None(), dex_pc) {}
 
   bool CanBeMoved() const OVERRIDE { return true; }
 
@@ -2194,7 +2205,7 @@
   DECLARE_INSTRUCTION(NullConstant);
 
  private:
-  HNullConstant() : HConstant(Primitive::kPrimNot) {}
+  explicit HNullConstant(uint32_t dex_pc = kNoDexPc) : HConstant(Primitive::kPrimNot, dex_pc) {}
 
   friend class HGraph;
   DISALLOW_COPY_AND_ASSIGN(HNullConstant);
@@ -2220,8 +2231,10 @@
   DECLARE_INSTRUCTION(IntConstant);
 
  private:
-  explicit HIntConstant(int32_t value) : HConstant(Primitive::kPrimInt), value_(value) {}
-  explicit HIntConstant(bool value) : HConstant(Primitive::kPrimInt), value_(value ? 1 : 0) {}
+  explicit HIntConstant(int32_t value, uint32_t dex_pc = kNoDexPc)
+      : HConstant(Primitive::kPrimInt, dex_pc), value_(value) {}
+  explicit HIntConstant(bool value, uint32_t dex_pc = kNoDexPc)
+      : HConstant(Primitive::kPrimInt, dex_pc), value_(value ? 1 : 0) {}
 
   const int32_t value_;
 
@@ -2249,7 +2262,8 @@
   DECLARE_INSTRUCTION(LongConstant);
 
  private:
-  explicit HLongConstant(int64_t value) : HConstant(Primitive::kPrimLong), value_(value) {}
+  explicit HLongConstant(int64_t value, uint32_t dex_pc = kNoDexPc)
+      : HConstant(Primitive::kPrimLong, dex_pc), value_(value) {}
 
   const int64_t value_;
 
@@ -2261,7 +2275,8 @@
 // two successors.
 class HIf : public HTemplateInstruction<1> {
  public:
-  explicit HIf(HInstruction* input) : HTemplateInstruction(SideEffects::None()) {
+  explicit HIf(HInstruction* input, uint32_t dex_pc = kNoDexPc)
+      : HTemplateInstruction(SideEffects::None(), dex_pc) {
     SetRawInputAt(0, input);
   }
 
@@ -2294,8 +2309,8 @@
     kExit,
   };
 
-  explicit HTryBoundary(BoundaryKind kind)
-      : HTemplateInstruction(SideEffects::None()), kind_(kind) {}
+  explicit HTryBoundary(BoundaryKind kind, uint32_t dex_pc = kNoDexPc)
+      : HTemplateInstruction(SideEffects::None(), dex_pc), kind_(kind) {}
 
   bool IsControlFlow() const OVERRIDE { return true; }
 
@@ -2352,21 +2367,17 @@
 // Deoptimize to interpreter, upon checking a condition.
 class HDeoptimize : public HTemplateInstruction<1> {
  public:
-  HDeoptimize(HInstruction* cond, uint32_t dex_pc)
-      : HTemplateInstruction(SideEffects::None()),
-        dex_pc_(dex_pc) {
+  explicit HDeoptimize(HInstruction* cond, uint32_t dex_pc)
+      : HTemplateInstruction(SideEffects::None(), dex_pc) {
     SetRawInputAt(0, cond);
   }
 
   bool NeedsEnvironment() const OVERRIDE { return true; }
   bool CanThrow() const OVERRIDE { return true; }
-  uint32_t GetDexPc() const OVERRIDE { return dex_pc_; }
 
   DECLARE_INSTRUCTION(Deoptimize);
 
  private:
-  uint32_t dex_pc_;
-
   DISALLOW_COPY_AND_ASSIGN(HDeoptimize);
 };
 
@@ -2375,7 +2386,8 @@
 // instructions that work with the dex cache.
 class HCurrentMethod : public HExpression<0> {
  public:
-  explicit HCurrentMethod(Primitive::Type type) : HExpression(type, SideEffects::None()) {}
+  explicit HCurrentMethod(Primitive::Type type, uint32_t dex_pc = kNoDexPc)
+      : HExpression(type, SideEffects::None(), dex_pc) {}
 
   DECLARE_INSTRUCTION(CurrentMethod);
 
@@ -2385,8 +2397,8 @@
 
 class HUnaryOperation : public HExpression<1> {
  public:
-  HUnaryOperation(Primitive::Type result_type, HInstruction* input)
-      : HExpression(result_type, SideEffects::None()) {
+  HUnaryOperation(Primitive::Type result_type, HInstruction* input, uint32_t dex_pc = kNoDexPc)
+      : HExpression(result_type, SideEffects::None(), dex_pc) {
     SetRawInputAt(0, input);
   }
 
@@ -2419,8 +2431,9 @@
   HBinaryOperation(Primitive::Type result_type,
                    HInstruction* left,
                    HInstruction* right,
-                   SideEffects side_effects = SideEffects::None())
-      : HExpression(result_type, side_effects) {
+                   SideEffects side_effects = SideEffects::None(),
+                   uint32_t dex_pc = kNoDexPc)
+      : HExpression(result_type, side_effects, dex_pc) {
     SetRawInputAt(0, left);
     SetRawInputAt(1, right);
   }
@@ -2512,8 +2525,8 @@
 
 class HCondition : public HBinaryOperation {
  public:
-  HCondition(HInstruction* first, HInstruction* second)
-      : HBinaryOperation(Primitive::kPrimBoolean, first, second),
+  HCondition(HInstruction* first, HInstruction* second, uint32_t dex_pc = kNoDexPc)
+      : HBinaryOperation(Primitive::kPrimBoolean, first, second, SideEffects::None(), dex_pc),
         needs_materialization_(true),
         bias_(ComparisonBias::kNoBias) {}
 
@@ -2564,18 +2577,20 @@
 // Instruction to check if two inputs are equal to each other.
 class HEqual : public HCondition {
  public:
-  HEqual(HInstruction* first, HInstruction* second)
-      : HCondition(first, second) {}
+  HEqual(HInstruction* first, HInstruction* second, uint32_t dex_pc = kNoDexPc)
+      : HCondition(first, second, dex_pc) {}
 
   bool IsCommutative() const OVERRIDE { return true; }
 
   template <typename T> bool Compute(T x, T y) const { return x == y; }
 
   HConstant* Evaluate(HIntConstant* x, HIntConstant* y) const OVERRIDE {
-    return GetBlock()->GetGraph()->GetIntConstant(Compute(x->GetValue(), y->GetValue()));
+    return GetBlock()->GetGraph()->GetIntConstant(
+        Compute(x->GetValue(), y->GetValue()), GetDexPc());
   }
   HConstant* Evaluate(HLongConstant* x, HLongConstant* y) const OVERRIDE {
-    return GetBlock()->GetGraph()->GetIntConstant(Compute(x->GetValue(), y->GetValue()));
+    return GetBlock()->GetGraph()->GetIntConstant(
+        Compute(x->GetValue(), y->GetValue()), GetDexPc());
   }
 
   DECLARE_INSTRUCTION(Equal);
@@ -2594,18 +2609,20 @@
 
 class HNotEqual : public HCondition {
  public:
-  HNotEqual(HInstruction* first, HInstruction* second)
-      : HCondition(first, second) {}
+  HNotEqual(HInstruction* first, HInstruction* second, uint32_t dex_pc = kNoDexPc)
+      : HCondition(first, second, dex_pc) {}
 
   bool IsCommutative() const OVERRIDE { return true; }
 
   template <typename T> bool Compute(T x, T y) const { return x != y; }
 
   HConstant* Evaluate(HIntConstant* x, HIntConstant* y) const OVERRIDE {
-    return GetBlock()->GetGraph()->GetIntConstant(Compute(x->GetValue(), y->GetValue()));
+    return GetBlock()->GetGraph()->GetIntConstant(
+        Compute(x->GetValue(), y->GetValue()), GetDexPc());
   }
   HConstant* Evaluate(HLongConstant* x, HLongConstant* y) const OVERRIDE {
-    return GetBlock()->GetGraph()->GetIntConstant(Compute(x->GetValue(), y->GetValue()));
+    return GetBlock()->GetGraph()->GetIntConstant(
+        Compute(x->GetValue(), y->GetValue()), GetDexPc());
   }
 
   DECLARE_INSTRUCTION(NotEqual);
@@ -2624,16 +2641,18 @@
 
 class HLessThan : public HCondition {
  public:
-  HLessThan(HInstruction* first, HInstruction* second)
-      : HCondition(first, second) {}
+  HLessThan(HInstruction* first, HInstruction* second, uint32_t dex_pc = kNoDexPc)
+      : HCondition(first, second, dex_pc) {}
 
   template <typename T> bool Compute(T x, T y) const { return x < y; }
 
   HConstant* Evaluate(HIntConstant* x, HIntConstant* y) const OVERRIDE {
-    return GetBlock()->GetGraph()->GetIntConstant(Compute(x->GetValue(), y->GetValue()));
+    return GetBlock()->GetGraph()->GetIntConstant(
+        Compute(x->GetValue(), y->GetValue()), GetDexPc());
   }
   HConstant* Evaluate(HLongConstant* x, HLongConstant* y) const OVERRIDE {
-    return GetBlock()->GetGraph()->GetIntConstant(Compute(x->GetValue(), y->GetValue()));
+    return GetBlock()->GetGraph()->GetIntConstant(
+        Compute(x->GetValue(), y->GetValue()), GetDexPc());
   }
 
   DECLARE_INSTRUCTION(LessThan);
@@ -2652,16 +2671,18 @@
 
 class HLessThanOrEqual : public HCondition {
  public:
-  HLessThanOrEqual(HInstruction* first, HInstruction* second)
-      : HCondition(first, second) {}
+  HLessThanOrEqual(HInstruction* first, HInstruction* second, uint32_t dex_pc = kNoDexPc)
+      : HCondition(first, second, dex_pc) {}
 
   template <typename T> bool Compute(T x, T y) const { return x <= y; }
 
   HConstant* Evaluate(HIntConstant* x, HIntConstant* y) const OVERRIDE {
-    return GetBlock()->GetGraph()->GetIntConstant(Compute(x->GetValue(), y->GetValue()));
+    return GetBlock()->GetGraph()->GetIntConstant(
+        Compute(x->GetValue(), y->GetValue()), GetDexPc());
   }
   HConstant* Evaluate(HLongConstant* x, HLongConstant* y) const OVERRIDE {
-    return GetBlock()->GetGraph()->GetIntConstant(Compute(x->GetValue(), y->GetValue()));
+    return GetBlock()->GetGraph()->GetIntConstant(
+        Compute(x->GetValue(), y->GetValue()), GetDexPc());
   }
 
   DECLARE_INSTRUCTION(LessThanOrEqual);
@@ -2680,16 +2701,18 @@
 
 class HGreaterThan : public HCondition {
  public:
-  HGreaterThan(HInstruction* first, HInstruction* second)
-      : HCondition(first, second) {}
+  HGreaterThan(HInstruction* first, HInstruction* second, uint32_t dex_pc = kNoDexPc)
+      : HCondition(first, second, dex_pc) {}
 
   template <typename T> bool Compute(T x, T y) const { return x > y; }
 
   HConstant* Evaluate(HIntConstant* x, HIntConstant* y) const OVERRIDE {
-    return GetBlock()->GetGraph()->GetIntConstant(Compute(x->GetValue(), y->GetValue()));
+    return GetBlock()->GetGraph()->GetIntConstant(
+        Compute(x->GetValue(), y->GetValue()), GetDexPc());
   }
   HConstant* Evaluate(HLongConstant* x, HLongConstant* y) const OVERRIDE {
-    return GetBlock()->GetGraph()->GetIntConstant(Compute(x->GetValue(), y->GetValue()));
+    return GetBlock()->GetGraph()->GetIntConstant(
+        Compute(x->GetValue(), y->GetValue()), GetDexPc());
   }
 
   DECLARE_INSTRUCTION(GreaterThan);
@@ -2708,16 +2731,18 @@
 
 class HGreaterThanOrEqual : public HCondition {
  public:
-  HGreaterThanOrEqual(HInstruction* first, HInstruction* second)
-      : HCondition(first, second) {}
+  HGreaterThanOrEqual(HInstruction* first, HInstruction* second, uint32_t dex_pc = kNoDexPc)
+      : HCondition(first, second, dex_pc) {}
 
   template <typename T> bool Compute(T x, T y) const { return x >= y; }
 
   HConstant* Evaluate(HIntConstant* x, HIntConstant* y) const OVERRIDE {
-    return GetBlock()->GetGraph()->GetIntConstant(Compute(x->GetValue(), y->GetValue()));
+    return GetBlock()->GetGraph()->GetIntConstant(
+        Compute(x->GetValue(), y->GetValue()), GetDexPc());
   }
   HConstant* Evaluate(HLongConstant* x, HLongConstant* y) const OVERRIDE {
-    return GetBlock()->GetGraph()->GetIntConstant(Compute(x->GetValue(), y->GetValue()));
+    return GetBlock()->GetGraph()->GetIntConstant(
+        Compute(x->GetValue(), y->GetValue()), GetDexPc());
   }
 
   DECLARE_INSTRUCTION(GreaterThanOrEqual);
@@ -2744,9 +2769,12 @@
            HInstruction* second,
            ComparisonBias bias,
            uint32_t dex_pc)
-      : HBinaryOperation(Primitive::kPrimInt, first, second, SideEffectsForArchRuntimeCalls(type)),
-        bias_(bias),
-        dex_pc_(dex_pc) {
+      : HBinaryOperation(Primitive::kPrimInt,
+                         first,
+                         second,
+                         SideEffectsForArchRuntimeCalls(type),
+                         dex_pc),
+        bias_(bias) {
     DCHECK_EQ(type, first->GetType());
     DCHECK_EQ(type, second->GetType());
   }
@@ -2755,10 +2783,12 @@
   int32_t Compute(T x, T y) const { return x == y ? 0 : x > y ? 1 : -1; }
 
   HConstant* Evaluate(HIntConstant* x, HIntConstant* y) const OVERRIDE {
-    return GetBlock()->GetGraph()->GetIntConstant(Compute(x->GetValue(), y->GetValue()));
+    return GetBlock()->GetGraph()->GetIntConstant(
+        Compute(x->GetValue(), y->GetValue()), GetDexPc());
   }
   HConstant* Evaluate(HLongConstant* x, HLongConstant* y) const OVERRIDE {
-    return GetBlock()->GetGraph()->GetIntConstant(Compute(x->GetValue(), y->GetValue()));
+    return GetBlock()->GetGraph()->GetIntConstant(
+        Compute(x->GetValue(), y->GetValue()), GetDexPc());
   }
 
   bool InstructionDataEquals(HInstruction* other) const OVERRIDE {
@@ -2769,7 +2799,6 @@
 
   bool IsGtBias() { return bias_ == ComparisonBias::kGtBias; }
 
-  uint32_t GetDexPc() const OVERRIDE { return dex_pc_; }
 
   static SideEffects SideEffectsForArchRuntimeCalls(Primitive::Type type) {
     // MIPS64 uses a runtime call for FP comparisons.
@@ -2780,7 +2809,6 @@
 
  private:
   const ComparisonBias bias_;
-  const uint32_t dex_pc_;
 
   DISALLOW_COPY_AND_ASSIGN(HCompare);
 };
@@ -2789,7 +2817,7 @@
 class HLocal : public HTemplateInstruction<0> {
  public:
   explicit HLocal(uint16_t reg_number)
-      : HTemplateInstruction(SideEffects::None()), reg_number_(reg_number) {}
+      : HTemplateInstruction(SideEffects::None(), kNoDexPc), reg_number_(reg_number) {}
 
   DECLARE_INSTRUCTION(Local);
 
@@ -2805,8 +2833,8 @@
 // Load a given local. The local is an input of this instruction.
 class HLoadLocal : public HExpression<1> {
  public:
-  HLoadLocal(HLocal* local, Primitive::Type type)
-      : HExpression(type, SideEffects::None()) {
+  HLoadLocal(HLocal* local, Primitive::Type type, uint32_t dex_pc = kNoDexPc)
+      : HExpression(type, SideEffects::None(), dex_pc) {
     SetRawInputAt(0, local);
   }
 
@@ -2822,7 +2850,8 @@
 // and the local.
 class HStoreLocal : public HTemplateInstruction<2> {
  public:
-  HStoreLocal(HLocal* local, HInstruction* value) : HTemplateInstruction(SideEffects::None()) {
+  HStoreLocal(HLocal* local, HInstruction* value, uint32_t dex_pc = kNoDexPc)
+      : HTemplateInstruction(SideEffects::None(), dex_pc) {
     SetRawInputAt(0, local);
     SetRawInputAt(1, value);
   }
@@ -2863,9 +2892,10 @@
   DECLARE_INSTRUCTION(FloatConstant);
 
  private:
-  explicit HFloatConstant(float value) : HConstant(Primitive::kPrimFloat), value_(value) {}
-  explicit HFloatConstant(int32_t value)
-      : HConstant(Primitive::kPrimFloat), value_(bit_cast<float, int32_t>(value)) {}
+  explicit HFloatConstant(float value, uint32_t dex_pc = kNoDexPc)
+      : HConstant(Primitive::kPrimFloat, dex_pc), value_(value) {}
+  explicit HFloatConstant(int32_t value, uint32_t dex_pc = kNoDexPc)
+      : HConstant(Primitive::kPrimFloat, dex_pc), value_(bit_cast<float, int32_t>(value)) {}
 
   const float value_;
 
@@ -2903,9 +2933,10 @@
   DECLARE_INSTRUCTION(DoubleConstant);
 
  private:
-  explicit HDoubleConstant(double value) : HConstant(Primitive::kPrimDouble), value_(value) {}
-  explicit HDoubleConstant(int64_t value)
-      : HConstant(Primitive::kPrimDouble), value_(bit_cast<double, int64_t>(value)) {}
+  explicit HDoubleConstant(double value, uint32_t dex_pc = kNoDexPc)
+      : HConstant(Primitive::kPrimDouble, dex_pc), value_(value) {}
+  explicit HDoubleConstant(int64_t value, uint32_t dex_pc = kNoDexPc)
+      : HConstant(Primitive::kPrimDouble, dex_pc), value_(bit_cast<double, int64_t>(value)) {}
 
   const double value_;
 
@@ -2952,7 +2983,6 @@
 
   Primitive::Type GetType() const OVERRIDE { return return_type_; }
 
-  uint32_t GetDexPc() const OVERRIDE { return dex_pc_; }
 
   uint32_t GetDexMethodIndex() const { return dex_method_index_; }
   const DexFile& GetDexFile() const { return GetEnvironment()->GetDexFile(); }
@@ -2985,11 +3015,10 @@
           uint32_t dex_method_index,
           InvokeType original_invoke_type)
     : HInstruction(
-          SideEffects::AllExceptGCDependency()),  // Assume write/read on all fields/arrays.
+          SideEffects::AllExceptGCDependency(), dex_pc),  // Assume write/read on all fields/arrays.
       number_of_arguments_(number_of_arguments),
       inputs_(arena, number_of_arguments),
       return_type_(return_type),
-      dex_pc_(dex_pc),
       dex_method_index_(dex_method_index),
       original_invoke_type_(original_invoke_type),
       intrinsic_(Intrinsics::kNone),
@@ -3006,7 +3035,6 @@
   uint32_t number_of_arguments_;
   GrowableArray<HUserRecord<HInstruction*> > inputs_;
   const Primitive::Type return_type_;
-  const uint32_t dex_pc_;
   const uint32_t dex_method_index_;
   const InvokeType original_invoke_type_;
   Intrinsics intrinsic_;
@@ -3307,15 +3335,13 @@
                uint16_t type_index,
                const DexFile& dex_file,
                QuickEntrypointEnum entrypoint)
-      : HExpression(Primitive::kPrimNot, SideEffects::CanTriggerGC()),
-        dex_pc_(dex_pc),
+      : HExpression(Primitive::kPrimNot, SideEffects::CanTriggerGC(), dex_pc),
         type_index_(type_index),
         dex_file_(dex_file),
         entrypoint_(entrypoint) {
     SetRawInputAt(0, current_method);
   }
 
-  uint32_t GetDexPc() const OVERRIDE { return dex_pc_; }
   uint16_t GetTypeIndex() const { return type_index_; }
   const DexFile& GetDexFile() const { return dex_file_; }
 
@@ -3334,7 +3360,6 @@
   DECLARE_INSTRUCTION(NewInstance);
 
  private:
-  const uint32_t dex_pc_;
   const uint16_t type_index_;
   const DexFile& dex_file_;
   const QuickEntrypointEnum entrypoint_;
@@ -3344,16 +3369,16 @@
 
 class HNeg : public HUnaryOperation {
  public:
-  HNeg(Primitive::Type result_type, HInstruction* input)
-      : HUnaryOperation(result_type, input) {}
+  HNeg(Primitive::Type result_type, HInstruction* input, uint32_t dex_pc = kNoDexPc)
+      : HUnaryOperation(result_type, input, dex_pc) {}
 
   template <typename T> T Compute(T x) const { return -x; }
 
   HConstant* Evaluate(HIntConstant* x) const OVERRIDE {
-    return GetBlock()->GetGraph()->GetIntConstant(Compute(x->GetValue()));
+    return GetBlock()->GetGraph()->GetIntConstant(Compute(x->GetValue()), GetDexPc());
   }
   HConstant* Evaluate(HLongConstant* x) const OVERRIDE {
-    return GetBlock()->GetGraph()->GetLongConstant(Compute(x->GetValue()));
+    return GetBlock()->GetGraph()->GetLongConstant(Compute(x->GetValue()), GetDexPc());
   }
 
   DECLARE_INSTRUCTION(Neg);
@@ -3370,8 +3395,7 @@
             uint16_t type_index,
             const DexFile& dex_file,
             QuickEntrypointEnum entrypoint)
-      : HExpression(Primitive::kPrimNot, SideEffects::CanTriggerGC()),
-        dex_pc_(dex_pc),
+      : HExpression(Primitive::kPrimNot, SideEffects::CanTriggerGC(), dex_pc),
         type_index_(type_index),
         dex_file_(dex_file),
         entrypoint_(entrypoint) {
@@ -3379,7 +3403,6 @@
     SetRawInputAt(1, current_method);
   }
 
-  uint32_t GetDexPc() const OVERRIDE { return dex_pc_; }
   uint16_t GetTypeIndex() const { return type_index_; }
   const DexFile& GetDexFile() const { return dex_file_; }
 
@@ -3396,7 +3419,6 @@
   DECLARE_INSTRUCTION(NewArray);
 
  private:
-  const uint32_t dex_pc_;
   const uint16_t type_index_;
   const DexFile& dex_file_;
   const QuickEntrypointEnum entrypoint_;
@@ -3406,18 +3428,23 @@
 
 class HAdd : public HBinaryOperation {
  public:
-  HAdd(Primitive::Type result_type, HInstruction* left, HInstruction* right)
-      : HBinaryOperation(result_type, left, right) {}
+  HAdd(Primitive::Type result_type,
+       HInstruction* left,
+       HInstruction* right,
+       uint32_t dex_pc = kNoDexPc)
+      : HBinaryOperation(result_type, left, right, SideEffects::None(), dex_pc) {}
 
   bool IsCommutative() const OVERRIDE { return true; }
 
   template <typename T> T Compute(T x, T y) const { return x + y; }
 
   HConstant* Evaluate(HIntConstant* x, HIntConstant* y) const OVERRIDE {
-    return GetBlock()->GetGraph()->GetIntConstant(Compute(x->GetValue(), y->GetValue()));
+    return GetBlock()->GetGraph()->GetIntConstant(
+        Compute(x->GetValue(), y->GetValue()), GetDexPc());
   }
   HConstant* Evaluate(HLongConstant* x, HLongConstant* y) const OVERRIDE {
-    return GetBlock()->GetGraph()->GetLongConstant(Compute(x->GetValue(), y->GetValue()));
+    return GetBlock()->GetGraph()->GetLongConstant(
+        Compute(x->GetValue(), y->GetValue()), GetDexPc());
   }
 
   DECLARE_INSTRUCTION(Add);
@@ -3428,16 +3455,21 @@
 
 class HSub : public HBinaryOperation {
  public:
-  HSub(Primitive::Type result_type, HInstruction* left, HInstruction* right)
-      : HBinaryOperation(result_type, left, right) {}
+  HSub(Primitive::Type result_type,
+       HInstruction* left,
+       HInstruction* right,
+       uint32_t dex_pc = kNoDexPc)
+      : HBinaryOperation(result_type, left, right, SideEffects::None(), dex_pc) {}
 
   template <typename T> T Compute(T x, T y) const { return x - y; }
 
   HConstant* Evaluate(HIntConstant* x, HIntConstant* y) const OVERRIDE {
-    return GetBlock()->GetGraph()->GetIntConstant(Compute(x->GetValue(), y->GetValue()));
+    return GetBlock()->GetGraph()->GetIntConstant(
+        Compute(x->GetValue(), y->GetValue()), GetDexPc());
   }
   HConstant* Evaluate(HLongConstant* x, HLongConstant* y) const OVERRIDE {
-    return GetBlock()->GetGraph()->GetLongConstant(Compute(x->GetValue(), y->GetValue()));
+    return GetBlock()->GetGraph()->GetLongConstant(
+        Compute(x->GetValue(), y->GetValue()), GetDexPc());
   }
 
   DECLARE_INSTRUCTION(Sub);
@@ -3448,18 +3480,23 @@
 
 class HMul : public HBinaryOperation {
  public:
-  HMul(Primitive::Type result_type, HInstruction* left, HInstruction* right)
-      : HBinaryOperation(result_type, left, right) {}
+  HMul(Primitive::Type result_type,
+       HInstruction* left,
+       HInstruction* right,
+       uint32_t dex_pc = kNoDexPc)
+      : HBinaryOperation(result_type, left, right, SideEffects::None(), dex_pc) {}
 
   bool IsCommutative() const OVERRIDE { return true; }
 
   template <typename T> T Compute(T x, T y) const { return x * y; }
 
   HConstant* Evaluate(HIntConstant* x, HIntConstant* y) const OVERRIDE {
-    return GetBlock()->GetGraph()->GetIntConstant(Compute(x->GetValue(), y->GetValue()));
+    return GetBlock()->GetGraph()->GetIntConstant(
+        Compute(x->GetValue(), y->GetValue()), GetDexPc());
   }
   HConstant* Evaluate(HLongConstant* x, HLongConstant* y) const OVERRIDE {
-    return GetBlock()->GetGraph()->GetLongConstant(Compute(x->GetValue(), y->GetValue()));
+    return GetBlock()->GetGraph()->GetLongConstant(
+        Compute(x->GetValue(), y->GetValue()), GetDexPc());
   }
 
   DECLARE_INSTRUCTION(Mul);
@@ -3470,9 +3507,11 @@
 
 class HDiv : public HBinaryOperation {
  public:
-  HDiv(Primitive::Type result_type, HInstruction* left, HInstruction* right, uint32_t dex_pc)
-      : HBinaryOperation(result_type, left, right, SideEffectsForArchRuntimeCalls()),
-        dex_pc_(dex_pc) {}
+  HDiv(Primitive::Type result_type,
+       HInstruction* left,
+       HInstruction* right,
+       uint32_t dex_pc)
+      : HBinaryOperation(result_type, left, right, SideEffectsForArchRuntimeCalls(), dex_pc) {}
 
   template <typename T>
   T Compute(T x, T y) const {
@@ -3484,14 +3523,14 @@
   }
 
   HConstant* Evaluate(HIntConstant* x, HIntConstant* y) const OVERRIDE {
-    return GetBlock()->GetGraph()->GetIntConstant(Compute(x->GetValue(), y->GetValue()));
+    return GetBlock()->GetGraph()->GetIntConstant(
+        Compute(x->GetValue(), y->GetValue()), GetDexPc());
   }
   HConstant* Evaluate(HLongConstant* x, HLongConstant* y) const OVERRIDE {
-    return GetBlock()->GetGraph()->GetLongConstant(Compute(x->GetValue(), y->GetValue()));
+    return GetBlock()->GetGraph()->GetLongConstant(
+        Compute(x->GetValue(), y->GetValue()), GetDexPc());
   }
 
-  uint32_t GetDexPc() const OVERRIDE { return dex_pc_; }
-
   static SideEffects SideEffectsForArchRuntimeCalls() {
     // The generated code can use a runtime call.
     return SideEffects::CanTriggerGC();
@@ -3500,16 +3539,16 @@
   DECLARE_INSTRUCTION(Div);
 
  private:
-  const uint32_t dex_pc_;
-
   DISALLOW_COPY_AND_ASSIGN(HDiv);
 };
 
 class HRem : public HBinaryOperation {
  public:
-  HRem(Primitive::Type result_type, HInstruction* left, HInstruction* right, uint32_t dex_pc)
-      : HBinaryOperation(result_type, left, right, SideEffectsForArchRuntimeCalls()),
-        dex_pc_(dex_pc) {}
+  HRem(Primitive::Type result_type,
+       HInstruction* left,
+       HInstruction* right,
+       uint32_t dex_pc)
+      : HBinaryOperation(result_type, left, right, SideEffectsForArchRuntimeCalls(), dex_pc) {}
 
   template <typename T>
   T Compute(T x, T y) const {
@@ -3521,13 +3560,14 @@
   }
 
   HConstant* Evaluate(HIntConstant* x, HIntConstant* y) const OVERRIDE {
-    return GetBlock()->GetGraph()->GetIntConstant(Compute(x->GetValue(), y->GetValue()));
+    return GetBlock()->GetGraph()->GetIntConstant(
+        Compute(x->GetValue(), y->GetValue()), GetDexPc());
   }
   HConstant* Evaluate(HLongConstant* x, HLongConstant* y) const OVERRIDE {
-    return GetBlock()->GetGraph()->GetLongConstant(Compute(x->GetValue(), y->GetValue()));
+    return GetBlock()->GetGraph()->GetLongConstant(
+        Compute(x->GetValue(), y->GetValue()), GetDexPc());
   }
 
-  uint32_t GetDexPc() const OVERRIDE { return dex_pc_; }
 
   static SideEffects SideEffectsForArchRuntimeCalls() {
     return SideEffects::CanTriggerGC();
@@ -3536,15 +3576,13 @@
   DECLARE_INSTRUCTION(Rem);
 
  private:
-  const uint32_t dex_pc_;
-
   DISALLOW_COPY_AND_ASSIGN(HRem);
 };
 
 class HDivZeroCheck : public HExpression<1> {
  public:
   HDivZeroCheck(HInstruction* value, uint32_t dex_pc)
-      : HExpression(value->GetType(), SideEffects::None()), dex_pc_(dex_pc) {
+      : HExpression(value->GetType(), SideEffects::None(), dex_pc) {
     SetRawInputAt(0, value);
   }
 
@@ -3560,20 +3598,19 @@
   bool NeedsEnvironment() const OVERRIDE { return true; }
   bool CanThrow() const OVERRIDE { return true; }
 
-  uint32_t GetDexPc() const OVERRIDE { return dex_pc_; }
-
   DECLARE_INSTRUCTION(DivZeroCheck);
 
  private:
-  const uint32_t dex_pc_;
-
   DISALLOW_COPY_AND_ASSIGN(HDivZeroCheck);
 };
 
 class HShl : public HBinaryOperation {
  public:
-  HShl(Primitive::Type result_type, HInstruction* left, HInstruction* right)
-      : HBinaryOperation(result_type, left, right) {}
+  HShl(Primitive::Type result_type,
+       HInstruction* left,
+       HInstruction* right,
+       uint32_t dex_pc = kNoDexPc)
+      : HBinaryOperation(result_type, left, right, SideEffects::None(), dex_pc) {}
 
   template <typename T, typename U, typename V>
   T Compute(T x, U y, V max_shift_value) const {
@@ -3584,17 +3621,17 @@
 
   HConstant* Evaluate(HIntConstant* x, HIntConstant* y) const OVERRIDE {
     return GetBlock()->GetGraph()->GetIntConstant(
-        Compute(x->GetValue(), y->GetValue(), kMaxIntShiftValue));
+        Compute(x->GetValue(), y->GetValue(), kMaxIntShiftValue), GetDexPc());
   }
   // There is no `Evaluate(HIntConstant* x, HLongConstant* y)`, as this
   // case is handled as `x << static_cast<int>(y)`.
   HConstant* Evaluate(HLongConstant* x, HIntConstant* y) const OVERRIDE {
     return GetBlock()->GetGraph()->GetLongConstant(
-        Compute(x->GetValue(), y->GetValue(), kMaxLongShiftValue));
+        Compute(x->GetValue(), y->GetValue(), kMaxLongShiftValue), GetDexPc());
   }
   HConstant* Evaluate(HLongConstant* x, HLongConstant* y) const OVERRIDE {
     return GetBlock()->GetGraph()->GetLongConstant(
-        Compute(x->GetValue(), y->GetValue(), kMaxLongShiftValue));
+        Compute(x->GetValue(), y->GetValue(), kMaxLongShiftValue), GetDexPc());
   }
 
   DECLARE_INSTRUCTION(Shl);
@@ -3605,8 +3642,11 @@
 
 class HShr : public HBinaryOperation {
  public:
-  HShr(Primitive::Type result_type, HInstruction* left, HInstruction* right)
-      : HBinaryOperation(result_type, left, right) {}
+  HShr(Primitive::Type result_type,
+       HInstruction* left,
+       HInstruction* right,
+       uint32_t dex_pc = kNoDexPc)
+      : HBinaryOperation(result_type, left, right, SideEffects::None(), dex_pc) {}
 
   template <typename T, typename U, typename V>
   T Compute(T x, U y, V max_shift_value) const {
@@ -3617,17 +3657,17 @@
 
   HConstant* Evaluate(HIntConstant* x, HIntConstant* y) const OVERRIDE {
     return GetBlock()->GetGraph()->GetIntConstant(
-        Compute(x->GetValue(), y->GetValue(), kMaxIntShiftValue));
+        Compute(x->GetValue(), y->GetValue(), kMaxIntShiftValue), GetDexPc());
   }
   // There is no `Evaluate(HIntConstant* x, HLongConstant* y)`, as this
   // case is handled as `x >> static_cast<int>(y)`.
   HConstant* Evaluate(HLongConstant* x, HIntConstant* y) const OVERRIDE {
     return GetBlock()->GetGraph()->GetLongConstant(
-        Compute(x->GetValue(), y->GetValue(), kMaxLongShiftValue));
+        Compute(x->GetValue(), y->GetValue(), kMaxLongShiftValue), GetDexPc());
   }
   HConstant* Evaluate(HLongConstant* x, HLongConstant* y) const OVERRIDE {
     return GetBlock()->GetGraph()->GetLongConstant(
-        Compute(x->GetValue(), y->GetValue(), kMaxLongShiftValue));
+        Compute(x->GetValue(), y->GetValue(), kMaxLongShiftValue), GetDexPc());
   }
 
   DECLARE_INSTRUCTION(Shr);
@@ -3638,8 +3678,11 @@
 
 class HUShr : public HBinaryOperation {
  public:
-  HUShr(Primitive::Type result_type, HInstruction* left, HInstruction* right)
-      : HBinaryOperation(result_type, left, right) {}
+  HUShr(Primitive::Type result_type,
+        HInstruction* left,
+        HInstruction* right,
+        uint32_t dex_pc = kNoDexPc)
+      : HBinaryOperation(result_type, left, right, SideEffects::None(), dex_pc) {}
 
   template <typename T, typename U, typename V>
   T Compute(T x, U y, V max_shift_value) const {
@@ -3651,17 +3694,17 @@
 
   HConstant* Evaluate(HIntConstant* x, HIntConstant* y) const OVERRIDE {
     return GetBlock()->GetGraph()->GetIntConstant(
-        Compute(x->GetValue(), y->GetValue(), kMaxIntShiftValue));
+        Compute(x->GetValue(), y->GetValue(), kMaxIntShiftValue), GetDexPc());
   }
   // There is no `Evaluate(HIntConstant* x, HLongConstant* y)`, as this
   // case is handled as `x >>> static_cast<int>(y)`.
   HConstant* Evaluate(HLongConstant* x, HIntConstant* y) const OVERRIDE {
     return GetBlock()->GetGraph()->GetLongConstant(
-        Compute(x->GetValue(), y->GetValue(), kMaxLongShiftValue));
+        Compute(x->GetValue(), y->GetValue(), kMaxLongShiftValue), GetDexPc());
   }
   HConstant* Evaluate(HLongConstant* x, HLongConstant* y) const OVERRIDE {
     return GetBlock()->GetGraph()->GetLongConstant(
-        Compute(x->GetValue(), y->GetValue(), kMaxLongShiftValue));
+        Compute(x->GetValue(), y->GetValue(), kMaxLongShiftValue), GetDexPc());
   }
 
   DECLARE_INSTRUCTION(UShr);
@@ -3672,8 +3715,11 @@
 
 class HAnd : public HBinaryOperation {
  public:
-  HAnd(Primitive::Type result_type, HInstruction* left, HInstruction* right)
-      : HBinaryOperation(result_type, left, right) {}
+  HAnd(Primitive::Type result_type,
+       HInstruction* left,
+       HInstruction* right,
+       uint32_t dex_pc = kNoDexPc)
+      : HBinaryOperation(result_type, left, right, SideEffects::None(), dex_pc) {}
 
   bool IsCommutative() const OVERRIDE { return true; }
 
@@ -3681,16 +3727,20 @@
   auto Compute(T x, U y) const -> decltype(x & y) { return x & y; }
 
   HConstant* Evaluate(HIntConstant* x, HIntConstant* y) const OVERRIDE {
-    return GetBlock()->GetGraph()->GetIntConstant(Compute(x->GetValue(), y->GetValue()));
+    return GetBlock()->GetGraph()->GetIntConstant(
+        Compute(x->GetValue(), y->GetValue()), GetDexPc());
   }
   HConstant* Evaluate(HIntConstant* x, HLongConstant* y) const OVERRIDE {
-    return GetBlock()->GetGraph()->GetLongConstant(Compute(x->GetValue(), y->GetValue()));
+    return GetBlock()->GetGraph()->GetLongConstant(
+        Compute(x->GetValue(), y->GetValue()), GetDexPc());
   }
   HConstant* Evaluate(HLongConstant* x, HIntConstant* y) const OVERRIDE {
-    return GetBlock()->GetGraph()->GetLongConstant(Compute(x->GetValue(), y->GetValue()));
+    return GetBlock()->GetGraph()->GetLongConstant(
+        Compute(x->GetValue(), y->GetValue()), GetDexPc());
   }
   HConstant* Evaluate(HLongConstant* x, HLongConstant* y) const OVERRIDE {
-    return GetBlock()->GetGraph()->GetLongConstant(Compute(x->GetValue(), y->GetValue()));
+    return GetBlock()->GetGraph()->GetLongConstant(
+        Compute(x->GetValue(), y->GetValue()), GetDexPc());
   }
 
   DECLARE_INSTRUCTION(And);
@@ -3701,8 +3751,11 @@
 
 class HOr : public HBinaryOperation {
  public:
-  HOr(Primitive::Type result_type, HInstruction* left, HInstruction* right)
-      : HBinaryOperation(result_type, left, right) {}
+  HOr(Primitive::Type result_type,
+      HInstruction* left,
+      HInstruction* right,
+      uint32_t dex_pc = kNoDexPc)
+      : HBinaryOperation(result_type, left, right, SideEffects::None(), dex_pc) {}
 
   bool IsCommutative() const OVERRIDE { return true; }
 
@@ -3710,16 +3763,20 @@
   auto Compute(T x, U y) const -> decltype(x | y) { return x | y; }
 
   HConstant* Evaluate(HIntConstant* x, HIntConstant* y) const OVERRIDE {
-    return GetBlock()->GetGraph()->GetIntConstant(Compute(x->GetValue(), y->GetValue()));
+    return GetBlock()->GetGraph()->GetIntConstant(
+        Compute(x->GetValue(), y->GetValue()), GetDexPc());
   }
   HConstant* Evaluate(HIntConstant* x, HLongConstant* y) const OVERRIDE {
-    return GetBlock()->GetGraph()->GetLongConstant(Compute(x->GetValue(), y->GetValue()));
+    return GetBlock()->GetGraph()->GetLongConstant(
+        Compute(x->GetValue(), y->GetValue()), GetDexPc());
   }
   HConstant* Evaluate(HLongConstant* x, HIntConstant* y) const OVERRIDE {
-    return GetBlock()->GetGraph()->GetLongConstant(Compute(x->GetValue(), y->GetValue()));
+    return GetBlock()->GetGraph()->GetLongConstant(
+        Compute(x->GetValue(), y->GetValue()), GetDexPc());
   }
   HConstant* Evaluate(HLongConstant* x, HLongConstant* y) const OVERRIDE {
-    return GetBlock()->GetGraph()->GetLongConstant(Compute(x->GetValue(), y->GetValue()));
+    return GetBlock()->GetGraph()->GetLongConstant(
+        Compute(x->GetValue(), y->GetValue()), GetDexPc());
   }
 
   DECLARE_INSTRUCTION(Or);
@@ -3730,8 +3787,11 @@
 
 class HXor : public HBinaryOperation {
  public:
-  HXor(Primitive::Type result_type, HInstruction* left, HInstruction* right)
-      : HBinaryOperation(result_type, left, right) {}
+  HXor(Primitive::Type result_type,
+       HInstruction* left,
+       HInstruction* right,
+       uint32_t dex_pc = kNoDexPc)
+      : HBinaryOperation(result_type, left, right, SideEffects::None(), dex_pc) {}
 
   bool IsCommutative() const OVERRIDE { return true; }
 
@@ -3739,16 +3799,20 @@
   auto Compute(T x, U y) const -> decltype(x ^ y) { return x ^ y; }
 
   HConstant* Evaluate(HIntConstant* x, HIntConstant* y) const OVERRIDE {
-    return GetBlock()->GetGraph()->GetIntConstant(Compute(x->GetValue(), y->GetValue()));
+    return GetBlock()->GetGraph()->GetIntConstant(
+        Compute(x->GetValue(), y->GetValue()), GetDexPc());
   }
   HConstant* Evaluate(HIntConstant* x, HLongConstant* y) const OVERRIDE {
-    return GetBlock()->GetGraph()->GetLongConstant(Compute(x->GetValue(), y->GetValue()));
+    return GetBlock()->GetGraph()->GetLongConstant(
+        Compute(x->GetValue(), y->GetValue()), GetDexPc());
   }
   HConstant* Evaluate(HLongConstant* x, HIntConstant* y) const OVERRIDE {
-    return GetBlock()->GetGraph()->GetLongConstant(Compute(x->GetValue(), y->GetValue()));
+    return GetBlock()->GetGraph()->GetLongConstant(
+        Compute(x->GetValue(), y->GetValue()), GetDexPc());
   }
   HConstant* Evaluate(HLongConstant* x, HLongConstant* y) const OVERRIDE {
-    return GetBlock()->GetGraph()->GetLongConstant(Compute(x->GetValue(), y->GetValue()));
+    return GetBlock()->GetGraph()->GetLongConstant(
+        Compute(x->GetValue(), y->GetValue()), GetDexPc());
   }
 
   DECLARE_INSTRUCTION(Xor);
@@ -3761,8 +3825,10 @@
 // the calling convention.
 class HParameterValue : public HExpression<0> {
  public:
-  HParameterValue(uint8_t index, Primitive::Type parameter_type, bool is_this = false)
-      : HExpression(parameter_type, SideEffects::None()),
+  HParameterValue(uint8_t index,
+                  Primitive::Type parameter_type,
+                  bool is_this = false)
+      : HExpression(parameter_type, SideEffects::None(), kNoDexPc),
         index_(index),
         is_this_(is_this),
         can_be_null_(!is_this) {}
@@ -3791,8 +3857,8 @@
 
 class HNot : public HUnaryOperation {
  public:
-  HNot(Primitive::Type result_type, HInstruction* input)
-      : HUnaryOperation(result_type, input) {}
+  HNot(Primitive::Type result_type, HInstruction* input, uint32_t dex_pc = kNoDexPc)
+      : HUnaryOperation(result_type, input, dex_pc) {}
 
   bool CanBeMoved() const OVERRIDE { return true; }
   bool InstructionDataEquals(HInstruction* other) const OVERRIDE {
@@ -3803,10 +3869,10 @@
   template <typename T> T Compute(T x) const { return ~x; }
 
   HConstant* Evaluate(HIntConstant* x) const OVERRIDE {
-    return GetBlock()->GetGraph()->GetIntConstant(Compute(x->GetValue()));
+    return GetBlock()->GetGraph()->GetIntConstant(Compute(x->GetValue()), GetDexPc());
   }
   HConstant* Evaluate(HLongConstant* x) const OVERRIDE {
-    return GetBlock()->GetGraph()->GetLongConstant(Compute(x->GetValue()));
+    return GetBlock()->GetGraph()->GetLongConstant(Compute(x->GetValue()), GetDexPc());
   }
 
   DECLARE_INSTRUCTION(Not);
@@ -3817,8 +3883,8 @@
 
 class HBooleanNot : public HUnaryOperation {
  public:
-  explicit HBooleanNot(HInstruction* input)
-      : HUnaryOperation(Primitive::Type::kPrimBoolean, input) {}
+  explicit HBooleanNot(HInstruction* input, uint32_t dex_pc = kNoDexPc)
+      : HUnaryOperation(Primitive::Type::kPrimBoolean, input, dex_pc) {}
 
   bool CanBeMoved() const OVERRIDE { return true; }
   bool InstructionDataEquals(HInstruction* other) const OVERRIDE {
@@ -3832,7 +3898,7 @@
   }
 
   HConstant* Evaluate(HIntConstant* x) const OVERRIDE {
-    return GetBlock()->GetGraph()->GetIntConstant(Compute(x->GetValue()));
+    return GetBlock()->GetGraph()->GetIntConstant(Compute(x->GetValue()), GetDexPc());
   }
   HConstant* Evaluate(HLongConstant* x ATTRIBUTE_UNUSED) const OVERRIDE {
     LOG(FATAL) << DebugName() << " is not defined for long values";
@@ -3849,8 +3915,9 @@
  public:
   // Instantiate a type conversion of `input` to `result_type`.
   HTypeConversion(Primitive::Type result_type, HInstruction* input, uint32_t dex_pc)
-      : HExpression(result_type, SideEffectsForArchRuntimeCalls(input->GetType(), result_type)),
-        dex_pc_(dex_pc) {
+      : HExpression(result_type,
+                    SideEffectsForArchRuntimeCalls(input->GetType(), result_type),
+                    dex_pc) {
     SetRawInputAt(0, input);
     DCHECK_NE(input->GetType(), result_type);
   }
@@ -3861,7 +3928,6 @@
 
   // Required by the x86 and ARM code generators when producing calls
   // to the runtime.
-  uint32_t GetDexPc() const OVERRIDE { return dex_pc_; }
 
   bool CanBeMoved() const OVERRIDE { return true; }
   bool InstructionDataEquals(HInstruction* other ATTRIBUTE_UNUSED) const OVERRIDE { return true; }
@@ -3885,8 +3951,6 @@
   DECLARE_INSTRUCTION(TypeConversion);
 
  private:
-  const uint32_t dex_pc_;
-
   DISALLOW_COPY_AND_ASSIGN(HTypeConversion);
 };
 
@@ -3894,8 +3958,12 @@
 
 class HPhi : public HInstruction {
  public:
-  HPhi(ArenaAllocator* arena, uint32_t reg_number, size_t number_of_inputs, Primitive::Type type)
-      : HInstruction(SideEffects::None()),
+  HPhi(ArenaAllocator* arena,
+       uint32_t reg_number,
+       size_t number_of_inputs,
+       Primitive::Type type,
+       uint32_t dex_pc = kNoDexPc)
+      : HInstruction(SideEffects::None(), dex_pc),
         inputs_(arena, number_of_inputs),
         reg_number_(reg_number),
         type_(type),
@@ -3973,7 +4041,7 @@
 class HNullCheck : public HExpression<1> {
  public:
   HNullCheck(HInstruction* value, uint32_t dex_pc)
-      : HExpression(value->GetType(), SideEffects::None()), dex_pc_(dex_pc) {
+      : HExpression(value->GetType(), SideEffects::None(), dex_pc) {
     SetRawInputAt(0, value);
   }
 
@@ -3989,13 +4057,10 @@
 
   bool CanBeNull() const OVERRIDE { return false; }
 
-  uint32_t GetDexPc() const OVERRIDE { return dex_pc_; }
 
   DECLARE_INSTRUCTION(NullCheck);
 
  private:
-  const uint32_t dex_pc_;
-
   DISALLOW_COPY_AND_ASSIGN(HNullCheck);
 };
 
@@ -4038,10 +4103,11 @@
                     bool is_volatile,
                     uint32_t field_idx,
                     const DexFile& dex_file,
-                    Handle<mirror::DexCache> dex_cache)
+                    Handle<mirror::DexCache> dex_cache,
+                    uint32_t dex_pc = kNoDexPc)
       : HExpression(
             field_type,
-            SideEffects::FieldReadOfType(field_type, is_volatile)),
+            SideEffects::FieldReadOfType(field_type, is_volatile), dex_pc),
         field_info_(field_offset, field_type, is_volatile, field_idx, dex_file, dex_cache) {
     SetRawInputAt(0, value);
   }
@@ -4083,9 +4149,10 @@
                     bool is_volatile,
                     uint32_t field_idx,
                     const DexFile& dex_file,
-                    Handle<mirror::DexCache> dex_cache)
+                    Handle<mirror::DexCache> dex_cache,
+                    uint32_t dex_pc = kNoDexPc)
       : HTemplateInstruction(
-          SideEffects::FieldWriteOfType(field_type, is_volatile)),
+          SideEffects::FieldWriteOfType(field_type, is_volatile), dex_pc),
         field_info_(field_offset, field_type, is_volatile, field_idx, dex_file, dex_cache),
         value_can_be_null_(true) {
     SetRawInputAt(0, object);
@@ -4115,8 +4182,11 @@
 
 class HArrayGet : public HExpression<2> {
  public:
-  HArrayGet(HInstruction* array, HInstruction* index, Primitive::Type type)
-      : HExpression(type, SideEffects::ArrayReadOfType(type)) {
+  HArrayGet(HInstruction* array,
+            HInstruction* index,
+            Primitive::Type type,
+            uint32_t dex_pc = kNoDexPc)
+      : HExpression(type, SideEffects::ArrayReadOfType(type), dex_pc) {
     SetRawInputAt(0, array);
     SetRawInputAt(1, index);
   }
@@ -4156,8 +4226,7 @@
             uint32_t dex_pc)
       : HTemplateInstruction(
             SideEffects::ArrayWriteOfType(expected_component_type).Union(
-                SideEffectsForArchRuntimeCalls(value->GetType()))),
-        dex_pc_(dex_pc),
+                SideEffectsForArchRuntimeCalls(value->GetType())), dex_pc),
         expected_component_type_(expected_component_type),
         needs_type_check_(value->GetType() == Primitive::kPrimNot),
         value_can_be_null_(true) {
@@ -4192,8 +4261,6 @@
   bool GetValueCanBeNull() const { return value_can_be_null_; }
   bool NeedsTypeCheck() const { return needs_type_check_; }
 
-  uint32_t GetDexPc() const OVERRIDE { return dex_pc_; }
-
   HInstruction* GetArray() const { return InputAt(0); }
   HInstruction* GetIndex() const { return InputAt(1); }
   HInstruction* GetValue() const { return InputAt(2); }
@@ -4216,7 +4283,6 @@
   DECLARE_INSTRUCTION(ArraySet);
 
  private:
-  const uint32_t dex_pc_;
   const Primitive::Type expected_component_type_;
   bool needs_type_check_;
   bool value_can_be_null_;
@@ -4226,8 +4292,8 @@
 
 class HArrayLength : public HExpression<1> {
  public:
-  explicit HArrayLength(HInstruction* array)
-      : HExpression(Primitive::kPrimInt, SideEffects::None()) {
+  explicit HArrayLength(HInstruction* array, uint32_t dex_pc = kNoDexPc)
+      : HExpression(Primitive::kPrimInt, SideEffects::None(), dex_pc) {
     // Note that arrays do not change length, so the instruction does not
     // depend on any write.
     SetRawInputAt(0, array);
@@ -4251,7 +4317,7 @@
 class HBoundsCheck : public HExpression<2> {
  public:
   HBoundsCheck(HInstruction* index, HInstruction* length, uint32_t dex_pc)
-      : HExpression(index->GetType(), SideEffects::None()), dex_pc_(dex_pc) {
+      : HExpression(index->GetType(), SideEffects::None(), dex_pc) {
     DCHECK(index->GetType() == Primitive::kPrimInt);
     SetRawInputAt(0, index);
     SetRawInputAt(1, length);
@@ -4267,13 +4333,10 @@
 
   bool CanThrow() const OVERRIDE { return true; }
 
-  uint32_t GetDexPc() const OVERRIDE { return dex_pc_; }
 
   DECLARE_INSTRUCTION(BoundsCheck);
 
  private:
-  const uint32_t dex_pc_;
-
   DISALLOW_COPY_AND_ASSIGN(HBoundsCheck);
 };
 
@@ -4286,7 +4349,8 @@
  */
 class HTemporary : public HTemplateInstruction<0> {
  public:
-  explicit HTemporary(size_t index) : HTemplateInstruction(SideEffects::None()), index_(index) {}
+  explicit HTemporary(size_t index, uint32_t dex_pc = kNoDexPc)
+      : HTemplateInstruction(SideEffects::None(), dex_pc), index_(index) {}
 
   size_t GetIndex() const { return index_; }
 
@@ -4300,28 +4364,24 @@
 
  private:
   const size_t index_;
-
   DISALLOW_COPY_AND_ASSIGN(HTemporary);
 };
 
 class HSuspendCheck : public HTemplateInstruction<0> {
  public:
   explicit HSuspendCheck(uint32_t dex_pc)
-      : HTemplateInstruction(SideEffects::CanTriggerGC()), dex_pc_(dex_pc), slow_path_(nullptr) {}
+      : HTemplateInstruction(SideEffects::CanTriggerGC(), dex_pc), slow_path_(nullptr) {}
 
   bool NeedsEnvironment() const OVERRIDE {
     return true;
   }
 
-  uint32_t GetDexPc() const OVERRIDE { return dex_pc_; }
   void SetSlowPath(SlowPathCode* slow_path) { slow_path_ = slow_path; }
   SlowPathCode* GetSlowPath() const { return slow_path_; }
 
   DECLARE_INSTRUCTION(SuspendCheck);
 
  private:
-  const uint32_t dex_pc_;
-
   // Only used for code generation, in order to share the same slow path between back edges
   // of a same loop.
   SlowPathCode* slow_path_;
@@ -4339,11 +4399,10 @@
              const DexFile& dex_file,
              bool is_referrers_class,
              uint32_t dex_pc)
-      : HExpression(Primitive::kPrimNot, SideEffectsForArchRuntimeCalls()),
+      : HExpression(Primitive::kPrimNot, SideEffectsForArchRuntimeCalls(), dex_pc),
         type_index_(type_index),
         dex_file_(dex_file),
         is_referrers_class_(is_referrers_class),
-        dex_pc_(dex_pc),
         generate_clinit_check_(false),
         loaded_class_rti_(ReferenceTypeInfo::CreateInvalid()) {
     SetRawInputAt(0, current_method);
@@ -4357,7 +4416,6 @@
 
   size_t ComputeHashCode() const OVERRIDE { return type_index_; }
 
-  uint32_t GetDexPc() const OVERRIDE { return dex_pc_; }
   uint16_t GetTypeIndex() const { return type_index_; }
   bool IsReferrersClass() const { return is_referrers_class_; }
   bool CanBeNull() const OVERRIDE { return false; }
@@ -4410,7 +4468,6 @@
   const uint16_t type_index_;
   const DexFile& dex_file_;
   const bool is_referrers_class_;
-  const uint32_t dex_pc_;
   // Whether this instruction must generate the initialization check.
   // Used for code generation.
   bool generate_clinit_check_;
@@ -4423,9 +4480,8 @@
 class HLoadString : public HExpression<1> {
  public:
   HLoadString(HCurrentMethod* current_method, uint32_t string_index, uint32_t dex_pc)
-      : HExpression(Primitive::kPrimNot, SideEffectsForArchRuntimeCalls()),
-        string_index_(string_index),
-        dex_pc_(dex_pc) {
+      : HExpression(Primitive::kPrimNot, SideEffectsForArchRuntimeCalls(), dex_pc),
+        string_index_(string_index) {
     SetRawInputAt(0, current_method);
   }
 
@@ -4437,7 +4493,6 @@
 
   size_t ComputeHashCode() const OVERRIDE { return string_index_; }
 
-  uint32_t GetDexPc() const OVERRIDE { return dex_pc_; }
   uint32_t GetStringIndex() const { return string_index_; }
 
   // TODO: Can we deopt or debug when we resolve a string?
@@ -4453,7 +4508,6 @@
 
  private:
   const uint32_t string_index_;
-  const uint32_t dex_pc_;
 
   DISALLOW_COPY_AND_ASSIGN(HLoadString);
 };
@@ -4466,8 +4520,8 @@
   HClinitCheck(HLoadClass* constant, uint32_t dex_pc)
       : HExpression(
             Primitive::kPrimNot,
-            SideEffects::AllChanges()),  // Assume write/read on all fields/arrays.
-        dex_pc_(dex_pc) {
+            SideEffects::AllChanges(),  // Assume write/read on all fields/arrays.
+            dex_pc) {
     SetRawInputAt(0, constant);
   }
 
@@ -4482,15 +4536,12 @@
     return true;
   }
 
-  uint32_t GetDexPc() const OVERRIDE { return dex_pc_; }
 
   HLoadClass* GetLoadClass() const { return InputAt(0)->AsLoadClass(); }
 
   DECLARE_INSTRUCTION(ClinitCheck);
 
  private:
-  const uint32_t dex_pc_;
-
   DISALLOW_COPY_AND_ASSIGN(HClinitCheck);
 };
 
@@ -4502,10 +4553,11 @@
                   bool is_volatile,
                   uint32_t field_idx,
                   const DexFile& dex_file,
-                  Handle<mirror::DexCache> dex_cache)
+                  Handle<mirror::DexCache> dex_cache,
+                  uint32_t dex_pc = kNoDexPc)
       : HExpression(
             field_type,
-            SideEffects::FieldReadOfType(field_type, is_volatile)),
+            SideEffects::FieldReadOfType(field_type, is_volatile), dex_pc),
         field_info_(field_offset, field_type, is_volatile, field_idx, dex_file, dex_cache) {
     SetRawInputAt(0, cls);
   }
@@ -4544,9 +4596,10 @@
                   bool is_volatile,
                   uint32_t field_idx,
                   const DexFile& dex_file,
-                  Handle<mirror::DexCache> dex_cache)
+                  Handle<mirror::DexCache> dex_cache,
+                  uint32_t dex_pc = kNoDexPc)
       : HTemplateInstruction(
-          SideEffects::FieldWriteOfType(field_type, is_volatile)),
+          SideEffects::FieldWriteOfType(field_type, is_volatile), dex_pc),
         field_info_(field_offset, field_type, is_volatile, field_idx, dex_file, dex_cache),
         value_can_be_null_(true) {
     SetRawInputAt(0, cls);
@@ -4574,7 +4627,8 @@
 // Implement the move-exception DEX instruction.
 class HLoadException : public HExpression<0> {
  public:
-  HLoadException() : HExpression(Primitive::kPrimNot, SideEffects::None()) {}
+  explicit HLoadException(uint32_t dex_pc = kNoDexPc)
+      : HExpression(Primitive::kPrimNot, SideEffects::None(), dex_pc) {}
 
   bool CanBeNull() const OVERRIDE { return false; }
 
@@ -4588,7 +4642,8 @@
 // Must not be removed because the runtime expects the TLS to get cleared.
 class HClearException : public HTemplateInstruction<0> {
  public:
-  HClearException() : HTemplateInstruction(SideEffects::AllWrites()) {}
+  explicit HClearException(uint32_t dex_pc = kNoDexPc)
+      : HTemplateInstruction(SideEffects::AllWrites(), dex_pc) {}
 
   DECLARE_INSTRUCTION(ClearException);
 
@@ -4599,7 +4654,7 @@
 class HThrow : public HTemplateInstruction<1> {
  public:
   HThrow(HInstruction* exception, uint32_t dex_pc)
-      : HTemplateInstruction(SideEffects::CanTriggerGC()), dex_pc_(dex_pc) {
+      : HTemplateInstruction(SideEffects::CanTriggerGC(), dex_pc) {
     SetRawInputAt(0, exception);
   }
 
@@ -4609,13 +4664,10 @@
 
   bool CanThrow() const OVERRIDE { return true; }
 
-  uint32_t GetDexPc() const OVERRIDE { return dex_pc_; }
 
   DECLARE_INSTRUCTION(Throw);
 
  private:
-  const uint32_t dex_pc_;
-
   DISALLOW_COPY_AND_ASSIGN(HThrow);
 };
 
@@ -4625,10 +4677,11 @@
               HLoadClass* constant,
               bool class_is_final,
               uint32_t dex_pc)
-      : HExpression(Primitive::kPrimBoolean, SideEffectsForArchRuntimeCalls(class_is_final)),
+      : HExpression(Primitive::kPrimBoolean,
+                    SideEffectsForArchRuntimeCalls(class_is_final),
+                    dex_pc),
         class_is_final_(class_is_final),
-        must_do_null_check_(true),
-        dex_pc_(dex_pc) {
+        must_do_null_check_(true) {
     SetRawInputAt(0, object);
     SetRawInputAt(1, constant);
   }
@@ -4643,8 +4696,6 @@
     return false;
   }
 
-  uint32_t GetDexPc() const OVERRIDE { return dex_pc_; }
-
   bool IsClassFinal() const { return class_is_final_; }
 
   // Used only in code generation.
@@ -4660,7 +4711,6 @@
  private:
   const bool class_is_final_;
   bool must_do_null_check_;
-  const uint32_t dex_pc_;
 
   DISALLOW_COPY_AND_ASSIGN(HInstanceOf);
 };
@@ -4669,8 +4719,11 @@
  public:
   // Constructs an HBoundType with the given upper_bound.
   // Ensures that the upper_bound is valid.
-  HBoundType(HInstruction* input, ReferenceTypeInfo upper_bound, bool upper_can_be_null)
-      : HExpression(Primitive::kPrimNot, SideEffects::None()),
+  HBoundType(HInstruction* input,
+             ReferenceTypeInfo upper_bound,
+             bool upper_can_be_null,
+             uint32_t dex_pc = kNoDexPc)
+      : HExpression(Primitive::kPrimNot, SideEffects::None(), dex_pc),
         upper_bound_(upper_bound),
         upper_can_be_null_(upper_can_be_null),
         can_be_null_(upper_can_be_null) {
@@ -4714,10 +4767,9 @@
              HLoadClass* constant,
              bool class_is_final,
              uint32_t dex_pc)
-      : HTemplateInstruction(SideEffects::CanTriggerGC()),
+      : HTemplateInstruction(SideEffects::CanTriggerGC(), dex_pc),
         class_is_final_(class_is_final),
-        must_do_null_check_(true),
-        dex_pc_(dex_pc) {
+        must_do_null_check_(true) {
     SetRawInputAt(0, object);
     SetRawInputAt(1, constant);
   }
@@ -4738,7 +4790,6 @@
   bool MustDoNullCheck() const { return must_do_null_check_; }
   void ClearMustDoNullCheck() { must_do_null_check_ = false; }
 
-  uint32_t GetDexPc() const OVERRIDE { return dex_pc_; }
 
   bool IsClassFinal() const { return class_is_final_; }
 
@@ -4747,16 +4798,15 @@
  private:
   const bool class_is_final_;
   bool must_do_null_check_;
-  const uint32_t dex_pc_;
 
   DISALLOW_COPY_AND_ASSIGN(HCheckCast);
 };
 
 class HMemoryBarrier : public HTemplateInstruction<0> {
  public:
-  explicit HMemoryBarrier(MemBarrierKind barrier_kind)
+  explicit HMemoryBarrier(MemBarrierKind barrier_kind, uint32_t dex_pc = kNoDexPc)
       : HTemplateInstruction(
-            SideEffects::AllWritesAndReads()),  // Assume write/read on all fields/arrays.
+            SideEffects::AllWritesAndReads(), dex_pc),  // Assume write/read on all fields/arrays.
         barrier_kind_(barrier_kind) {}
 
   MemBarrierKind GetBarrierKind() { return barrier_kind_; }
@@ -4778,8 +4828,8 @@
 
   HMonitorOperation(HInstruction* object, OperationKind kind, uint32_t dex_pc)
     : HTemplateInstruction(
-          SideEffects::AllExceptGCDependency()),  // Assume write/read on all fields/arrays.
-      kind_(kind), dex_pc_(dex_pc) {
+          SideEffects::AllExceptGCDependency(), dex_pc),  // Assume write/read on all fields/arrays.
+      kind_(kind) {
     SetRawInputAt(0, object);
   }
 
@@ -4793,7 +4843,6 @@
     return IsEnter();
   }
 
-  uint32_t GetDexPc() const OVERRIDE { return dex_pc_; }
 
   bool IsEnter() const { return kind_ == kEnter; }
 
@@ -4801,7 +4850,6 @@
 
  private:
   const OperationKind kind_;
-  const uint32_t dex_pc_;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(HMonitorOperation);
@@ -4816,7 +4864,8 @@
  */
 class HFakeString : public HTemplateInstruction<0> {
  public:
-  HFakeString() : HTemplateInstruction(SideEffects::None()) {}
+  explicit HFakeString(uint32_t dex_pc = kNoDexPc)
+      : HTemplateInstruction(SideEffects::None(), dex_pc) {}
 
   Primitive::Type GetType() const OVERRIDE { return Primitive::kPrimNot; }
 
@@ -4904,8 +4953,8 @@
 
 class HParallelMove : public HTemplateInstruction<0> {
  public:
-  explicit HParallelMove(ArenaAllocator* arena)
-      : HTemplateInstruction(SideEffects::None()), moves_(arena, kDefaultNumberOfMoves) {}
+  explicit HParallelMove(ArenaAllocator* arena, uint32_t dex_pc = kNoDexPc)
+      : HTemplateInstruction(SideEffects::None(), dex_pc), moves_(arena, kDefaultNumberOfMoves) {}
 
   void AddMove(Location source,
                Location destination,
@@ -4955,6 +5004,14 @@
   DISALLOW_COPY_AND_ASSIGN(HParallelMove);
 };
 
+}  // namespace art
+
+#ifdef ART_ENABLE_CODEGEN_x86
+#include "nodes_x86.h"
+#endif
+
+namespace art {
+
 class HGraphVisitor : public ValueObject {
  public:
   explicit HGraphVisitor(HGraph* graph) : graph_(graph) {}
diff --git a/compiler/optimizing/nodes_x86.h b/compiler/optimizing/nodes_x86.h
new file mode 100644
index 0000000..ddc5730
--- /dev/null
+++ b/compiler/optimizing/nodes_x86.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_COMPILER_OPTIMIZING_NODES_X86_H_
+#define ART_COMPILER_OPTIMIZING_NODES_X86_H_
+
+namespace art {
+
+// Compute the address of the method for X86 Constant area support.
+class HX86ComputeBaseMethodAddress : public HExpression<0> {
+ public:
+  // Treat the value as an int32_t, but it is really a 32 bit native pointer.
+  HX86ComputeBaseMethodAddress() : HExpression(Primitive::kPrimInt, SideEffects::None()) {}
+
+  DECLARE_INSTRUCTION(X86ComputeBaseMethodAddress);
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(HX86ComputeBaseMethodAddress);
+};
+
+// Load a constant value from the constant table.
+class HX86LoadFromConstantTable : public HExpression<2> {
+ public:
+  HX86LoadFromConstantTable(HX86ComputeBaseMethodAddress* method_base,
+                            HConstant* constant,
+                            bool needs_materialization = true)
+      : HExpression(constant->GetType(), SideEffects::None()),
+        needs_materialization_(needs_materialization) {
+    SetRawInputAt(0, method_base);
+    SetRawInputAt(1, constant);
+  }
+
+  bool NeedsMaterialization() const { return needs_materialization_; }
+
+  HX86ComputeBaseMethodAddress* GetBaseMethodAddress() const {
+    return InputAt(0)->AsX86ComputeBaseMethodAddress();
+  }
+
+  HConstant* GetConstant() const {
+    return InputAt(1)->AsConstant();
+  }
+
+  DECLARE_INSTRUCTION(X86LoadFromConstantTable);
+
+ private:
+  const bool needs_materialization_;
+
+  DISALLOW_COPY_AND_ASSIGN(HX86LoadFromConstantTable);
+};
+
+}  // namespace art
+
+#endif  // ART_COMPILER_OPTIMIZING_NODES_X86_H_
diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc
index 91b03d4..f549ba8 100644
--- a/compiler/optimizing/optimizing_compiler.cc
+++ b/compiler/optimizing/optimizing_compiler.cc
@@ -23,6 +23,10 @@
 #include "instruction_simplifier_arm64.h"
 #endif
 
+#ifdef ART_ENABLE_CODEGEN_x86
+#include "constant_area_fixups_x86.h"
+#endif
+
 #include "art_method-inl.h"
 #include "base/arena_allocator.h"
 #include "base/arena_containers.h"
@@ -424,6 +428,17 @@
       break;
     }
 #endif
+#ifdef ART_ENABLE_CODEGEN_x86
+    case kX86: {
+      x86::ConstantAreaFixups* constant_area_fixups =
+          new (arena) x86::ConstantAreaFixups(graph, stats);
+      HOptimization* x86_optimizations[] = {
+        constant_area_fixups
+      };
+      RunOptimizations(x86_optimizations, arraysize(x86_optimizations), pass_observer);
+      break;
+    }
+#endif
     default:
       break;
   }
diff --git a/compiler/utils/x86/assembler_x86.cc b/compiler/utils/x86/assembler_x86.cc
index a03f857..e3962b4 100644
--- a/compiler/utils/x86/assembler_x86.cc
+++ b/compiler/utils/x86/assembler_x86.cc
@@ -1750,6 +1750,10 @@
   for (int i = 1; i < length; i++) {
     EmitUint8(operand.encoding_[i]);
   }
+  AssemblerFixup* fixup = operand.GetFixup();
+  if (fixup != nullptr) {
+    EmitFixup(fixup);
+  }
 }
 
 
@@ -2322,5 +2326,56 @@
 #undef __
 }
 
+void X86Assembler::AddConstantArea() {
+  const std::vector<int32_t>& area = constant_area_.GetBuffer();
+  // Generate the data for the literal area.
+  for (size_t i = 0, e = area.size(); i < e; i++) {
+    AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+    EmitInt32(area[i]);
+  }
+}
+
+int ConstantArea::AddInt32(int32_t v) {
+  for (size_t i = 0, e = buffer_.size(); i < e; i++) {
+    if (v == buffer_[i]) {
+      return i * kEntrySize;
+    }
+  }
+
+  // Didn't match anything.
+  int result = buffer_.size() * kEntrySize;
+  buffer_.push_back(v);
+  return result;
+}
+
+int ConstantArea::AddInt64(int64_t v) {
+  int32_t v_low = Low32Bits(v);
+  int32_t v_high = High32Bits(v);
+  if (buffer_.size() > 1) {
+    // Ensure we don't pass the end of the buffer.
+    for (size_t i = 0, e = buffer_.size() - 1; i < e; i++) {
+      if (v_low == buffer_[i] && v_high == buffer_[i + 1]) {
+        return i * kEntrySize;
+      }
+    }
+  }
+
+  // Didn't match anything.
+  int result = buffer_.size() * kEntrySize;
+  buffer_.push_back(v_low);
+  buffer_.push_back(v_high);
+  return result;
+}
+
+int ConstantArea::AddDouble(double v) {
+  // Treat the value as a 64-bit integer value.
+  return AddInt64(bit_cast<int64_t, double>(v));
+}
+
+int ConstantArea::AddFloat(float v) {
+  // Treat the value as a 32-bit integer value.
+  return AddInt32(bit_cast<int32_t, float>(v));
+}
+
 }  // namespace x86
 }  // namespace art
diff --git a/compiler/utils/x86/assembler_x86.h b/compiler/utils/x86/assembler_x86.h
index 0c90f28..7d7b3d3 100644
--- a/compiler/utils/x86/assembler_x86.h
+++ b/compiler/utils/x86/assembler_x86.h
@@ -86,7 +86,7 @@
 
  protected:
   // Operand can be sub classed (e.g: Address).
-  Operand() : length_(0) { }
+  Operand() : length_(0), fixup_(nullptr) { }
 
   void SetModRM(int mod_in, Register rm_in) {
     CHECK_EQ(mod_in & ~3, 0);
@@ -113,11 +113,23 @@
     length_ += disp_size;
   }
 
+  AssemblerFixup* GetFixup() const {
+    return fixup_;
+  }
+
+  void SetFixup(AssemblerFixup* fixup) {
+    fixup_ = fixup;
+  }
+
  private:
   uint8_t length_;
   uint8_t encoding_[6];
 
-  explicit Operand(Register reg) { SetModRM(3, reg); }
+  // A fixup can be associated with the operand, in order to be applied after the
+  // code has been generated. This is used for constant area fixups.
+  AssemblerFixup* fixup_;
+
+  explicit Operand(Register reg) : fixup_(nullptr) { SetModRM(3, reg); }
 
   // Get the operand encoding byte at the given index.
   uint8_t encoding_at(int index_in) const {
@@ -136,6 +148,11 @@
     Init(base_in, disp);
   }
 
+  Address(Register base_in, int32_t disp, AssemblerFixup *fixup) {
+    Init(base_in, disp);
+    SetFixup(fixup);
+  }
+
   Address(Register base_in, Offset disp) {
     Init(base_in, disp.Int32Value());
   }
@@ -226,6 +243,50 @@
   DISALLOW_COPY_AND_ASSIGN(NearLabel);
 };
 
+/**
+ * Class to handle constant area values.
+ */
+class ConstantArea {
+ public:
+  ConstantArea() {}
+
+  // Add a double to the constant area, returning the offset into
+  // the constant area where the literal resides.
+  int AddDouble(double v);
+
+  // Add a float to the constant area, returning the offset into
+  // the constant area where the literal resides.
+  int AddFloat(float v);
+
+  // Add an int32_t to the constant area, returning the offset into
+  // the constant area where the literal resides.
+  int AddInt32(int32_t v);
+
+  // Add an int64_t to the constant area, returning the offset into
+  // the constant area where the literal resides.
+  int AddInt64(int64_t v);
+
+  bool IsEmpty() const {
+    return buffer_.size() == 0;
+  }
+
+  const std::vector<int32_t>& GetBuffer() const {
+    return buffer_;
+  }
+
+  void AddFixup(AssemblerFixup* fixup) {
+    fixups_.push_back(fixup);
+  }
+
+  const std::vector<AssemblerFixup*>& GetFixups() const {
+    return fixups_;
+  }
+
+ private:
+  static constexpr size_t kEntrySize = sizeof(int32_t);
+  std::vector<int32_t> buffer_;
+  std::vector<AssemblerFixup*> fixups_;
+};
 
 class X86Assembler FINAL : public Assembler {
  public:
@@ -667,6 +728,29 @@
     }
   }
 
+  // Add a double to the constant area, returning the offset into
+  // the constant area where the literal resides.
+  int AddDouble(double v) { return constant_area_.AddDouble(v); }
+
+  // Add a float to the constant area, returning the offset into
+  // the constant area where the literal resides.
+  int AddFloat(float v)   { return constant_area_.AddFloat(v); }
+
+  // Add an int32_t to the constant area, returning the offset into
+  // the constant area where the literal resides.
+  int AddInt32(int32_t v) { return constant_area_.AddInt32(v); }
+
+  // Add an int64_t to the constant area, returning the offset into
+  // the constant area where the literal resides.
+  int AddInt64(int64_t v) { return constant_area_.AddInt64(v); }
+
+  // Add the contents of the constant area to the assembler buffer.
+  void AddConstantArea();
+
+  // Is the constant area empty? Return true if there are no literals in the constant area.
+  bool IsConstantAreaEmpty() const { return constant_area_.IsEmpty(); }
+  void AddConstantAreaFixup(AssemblerFixup* fixup) { constant_area_.AddFixup(fixup); }
+
  private:
   inline void EmitUint8(uint8_t value);
   inline void EmitInt32(int32_t value);
@@ -685,6 +769,8 @@
   void EmitGenericShift(int rm, const Operand& operand, const Immediate& imm);
   void EmitGenericShift(int rm, const Operand& operand, Register shifter);
 
+  ConstantArea constant_area_;
+
   DISALLOW_COPY_AND_ASSIGN(X86Assembler);
 };
 
diff --git a/runtime/java_vm_ext.cc b/runtime/java_vm_ext.cc
index 92eef39..63e8887 100644
--- a/runtime/java_vm_ext.cc
+++ b/runtime/java_vm_ext.cc
@@ -580,9 +580,12 @@
 }
 
 inline bool JavaVMExt::MayAccessWeakGlobalsUnlocked(Thread* self) const {
-  return kUseReadBarrier
-      ? self->GetWeakRefAccessEnabled()
-      : allow_accessing_weak_globals_.LoadSequentiallyConsistent();
+  if (kUseReadBarrier) {
+    // self can be null during a runtime shutdown. ~Runtime()->~ClassLinker()->DecodeWeakGlobal().
+    return self != nullptr ? self->GetWeakRefAccessEnabled() : true;
+  } else {
+    return allow_accessing_weak_globals_.LoadSequentiallyConsistent();
+  }
 }
 
 mirror::Object* JavaVMExt::DecodeWeakGlobal(Thread* self, IndirectRef ref) {