OSDN Git Service

Try to substitute constructor chains for IPUTs.
authorVladimir Marko <vmarko@google.com>
Thu, 4 Feb 2016 19:46:56 +0000 (19:46 +0000)
committerVladimir Marko <vmarko@google.com>
Tue, 9 Feb 2016 19:57:41 +0000 (19:57 +0000)
Match a constructor chain where each constructor either
forwards some or all of its arguments to the next (i.e.
superclass constructor or a constructor in the same class)
and may pass extra zeros (of any type, including null),
followed by any number of IPUTs on "this", storing either
arguments or zeros, until we reach the contructor of
java.lang.Object.

When collecting IPUTs from the constructor chain, remove
any IPUTs that store the same field as an IPUT that comes
later. This is safe in this case even if those IPUTs store
volatile fields because the uninitialized object reference
wasn't allowed to escape yet. Also remove any IPUTs that
store zero values as the allocated object is already zero
initialized.

Change-Id: If93022310bf04fe38ee741665ac4a65d4c2bb25f

15 files changed:
compiler/dex/quick/dex_file_method_inliner.cc
compiler/optimizing/inliner.cc
compiler/optimizing/inliner.h
compiler/optimizing/intrinsics.cc
runtime/dex_instruction_utils.h
runtime/quick/inline_method_analyser.cc
runtime/quick/inline_method_analyser.h
test/569-checker-pattern-replacement/src-multidex/Base.java [new file with mode: 0644]
test/569-checker-pattern-replacement/src-multidex/BaseWithFinalField.java [new file with mode: 0644]
test/569-checker-pattern-replacement/src-multidex/Derived.java [new file with mode: 0644]
test/569-checker-pattern-replacement/src-multidex/DerivedInSecondDex.java [new file with mode: 0644]
test/569-checker-pattern-replacement/src-multidex/DerivedWithFinalField.java [new file with mode: 0644]
test/569-checker-pattern-replacement/src/BaseInMainDex.java [new file with mode: 0644]
test/569-checker-pattern-replacement/src/Main.java
test/Android.run-test.mk

index 22b178c..209f101 100644 (file)
@@ -875,6 +875,7 @@ bool DexFileMethodInliner::GenInline(MIRGraph* mir_graph, BasicBlock* bb, MIR* i
       move_result = mir_graph->FindMoveResult(bb, invoke);
       result = GenInlineIPut(mir_graph, bb, invoke, move_result, method);
       break;
+    case kInlineOpConstructor:
     case kInlineStringInit:
       return false;
     default:
index 9b91b53..34a5e34 100644 (file)
@@ -612,8 +612,9 @@ bool HInliner::TryPatternSubstitution(HInvoke* invoke_instruction,
         // TODO: Needs null check.
         return false;
       }
+      Handle<mirror::DexCache> dex_cache(handles_->NewHandle(resolved_method->GetDexCache()));
       HInstruction* obj = GetInvokeInputForArgVRegIndex(invoke_instruction, data.object_arg);
-      HInstanceFieldGet* iget = CreateInstanceFieldGet(resolved_method, data.field_idx, obj);
+      HInstanceFieldGet* iget = CreateInstanceFieldGet(dex_cache, data.field_idx, obj);
       DCHECK_EQ(iget->GetFieldOffset().Uint32Value(), data.field_offset);
       DCHECK_EQ(iget->IsVolatile() ? 1u : 0u, data.is_volatile);
       invoke_instruction->GetBlock()->InsertInstructionBefore(iget, invoke_instruction);
@@ -626,9 +627,10 @@ bool HInliner::TryPatternSubstitution(HInvoke* invoke_instruction,
         // TODO: Needs null check.
         return false;
       }
+      Handle<mirror::DexCache> dex_cache(handles_->NewHandle(resolved_method->GetDexCache()));
       HInstruction* obj = GetInvokeInputForArgVRegIndex(invoke_instruction, data.object_arg);
       HInstruction* value = GetInvokeInputForArgVRegIndex(invoke_instruction, data.src_arg);
-      HInstanceFieldSet* iput = CreateInstanceFieldSet(resolved_method, data.field_idx, obj, value);
+      HInstanceFieldSet* iput = CreateInstanceFieldSet(dex_cache, data.field_idx, obj, value);
       DCHECK_EQ(iput->GetFieldOffset().Uint32Value(), data.field_offset);
       DCHECK_EQ(iput->IsVolatile() ? 1u : 0u, data.is_volatile);
       invoke_instruction->GetBlock()->InsertInstructionBefore(iput, invoke_instruction);
@@ -638,6 +640,59 @@ bool HInliner::TryPatternSubstitution(HInvoke* invoke_instruction,
       }
       break;
     }
+    case kInlineOpConstructor: {
+      const InlineConstructorData& data = inline_method.d.constructor_data;
+      // Get the indexes to arrays for easier processing.
+      uint16_t iput_field_indexes[] = {
+          data.iput0_field_index, data.iput1_field_index, data.iput2_field_index
+      };
+      uint16_t iput_args[] = { data.iput0_arg, data.iput1_arg, data.iput2_arg };
+      static_assert(arraysize(iput_args) == arraysize(iput_field_indexes), "Size mismatch");
+      // Count valid field indexes.
+      size_t number_of_iputs = 0u;
+      while (number_of_iputs != arraysize(iput_field_indexes) &&
+          iput_field_indexes[number_of_iputs] != DexFile::kDexNoIndex16) {
+        // Check that there are no duplicate valid field indexes.
+        DCHECK_EQ(0, std::count(iput_field_indexes + number_of_iputs + 1,
+                                iput_field_indexes + arraysize(iput_field_indexes),
+                                iput_field_indexes[number_of_iputs]));
+        ++number_of_iputs;
+      }
+      // Check that there are no valid field indexes in the rest of the array.
+      DCHECK_EQ(0, std::count_if(iput_field_indexes + number_of_iputs,
+                                 iput_field_indexes + arraysize(iput_field_indexes),
+                                 [](uint16_t index) { return index != DexFile::kDexNoIndex16; }));
+
+      // Create HInstanceFieldSet for each IPUT that stores non-zero data.
+      Handle<mirror::DexCache> dex_cache;
+      HInstruction* obj = GetInvokeInputForArgVRegIndex(invoke_instruction, /* this */ 0u);
+      bool needs_constructor_barrier = false;
+      for (size_t i = 0; i != number_of_iputs; ++i) {
+        HInstruction* value = GetInvokeInputForArgVRegIndex(invoke_instruction, iput_args[i]);
+        if (!value->IsConstant() ||
+            (!value->AsConstant()->IsZero() && !value->IsNullConstant())) {
+          if (dex_cache.GetReference() == nullptr) {
+            dex_cache = handles_->NewHandle(resolved_method->GetDexCache());
+          }
+          uint16_t field_index = iput_field_indexes[i];
+          HInstanceFieldSet* iput = CreateInstanceFieldSet(dex_cache, field_index, obj, value);
+          invoke_instruction->GetBlock()->InsertInstructionBefore(iput, invoke_instruction);
+
+          // Check whether the field is final. If it is, we need to add a barrier.
+          size_t pointer_size = InstructionSetPointerSize(codegen_->GetInstructionSet());
+          ArtField* resolved_field = dex_cache->GetResolvedField(field_index, pointer_size);
+          DCHECK(resolved_field != nullptr);
+          if (resolved_field->IsFinal()) {
+            needs_constructor_barrier = true;
+          }
+        }
+      }
+      if (needs_constructor_barrier) {
+        HMemoryBarrier* barrier = new (graph_->GetArena()) HMemoryBarrier(kStoreStore, kNoDexPc);
+        invoke_instruction->GetBlock()->InsertInstructionBefore(barrier, invoke_instruction);
+      }
+      break;
+    }
     default:
       LOG(FATAL) << "UNREACHABLE";
       UNREACHABLE();
@@ -652,11 +707,10 @@ bool HInliner::TryPatternSubstitution(HInvoke* invoke_instruction,
   return true;
 }
 
-HInstanceFieldGet* HInliner::CreateInstanceFieldGet(ArtMethod* resolved_method,
+HInstanceFieldGet* HInliner::CreateInstanceFieldGet(Handle<mirror::DexCache> dex_cache,
                                                     uint32_t field_index,
                                                     HInstruction* obj)
     SHARED_REQUIRES(Locks::mutator_lock_) {
-  Handle<mirror::DexCache> dex_cache(handles_->NewHandle(resolved_method->GetDexCache()));
   size_t pointer_size = InstructionSetPointerSize(codegen_->GetInstructionSet());
   ArtField* resolved_field = dex_cache->GetResolvedField(field_index, pointer_size);
   DCHECK(resolved_field != nullptr);
@@ -667,7 +721,7 @@ HInstanceFieldGet* HInliner::CreateInstanceFieldGet(ArtMethod* resolved_method,
       resolved_field->IsVolatile(),
       field_index,
       resolved_field->GetDeclaringClass()->GetDexClassDefIndex(),
-      *resolved_method->GetDexFile(),
+      *dex_cache->GetDexFile(),
       dex_cache,
       // Read barrier generates a runtime call in slow path and we need a valid
       // dex pc for the associated stack map. 0 is bogus but valid. Bug: 26854537.
@@ -679,12 +733,11 @@ HInstanceFieldGet* HInliner::CreateInstanceFieldGet(ArtMethod* resolved_method,
   return iget;
 }
 
-HInstanceFieldSet* HInliner::CreateInstanceFieldSet(ArtMethod* resolved_method,
+HInstanceFieldSet* HInliner::CreateInstanceFieldSet(Handle<mirror::DexCache> dex_cache,
                                                     uint32_t field_index,
                                                     HInstruction* obj,
                                                     HInstruction* value)
     SHARED_REQUIRES(Locks::mutator_lock_) {
-  Handle<mirror::DexCache> dex_cache(handles_->NewHandle(resolved_method->GetDexCache()));
   size_t pointer_size = InstructionSetPointerSize(codegen_->GetInstructionSet());
   ArtField* resolved_field = dex_cache->GetResolvedField(field_index, pointer_size);
   DCHECK(resolved_field != nullptr);
@@ -696,7 +749,7 @@ HInstanceFieldSet* HInliner::CreateInstanceFieldSet(ArtMethod* resolved_method,
       resolved_field->IsVolatile(),
       field_index,
       resolved_field->GetDeclaringClass()->GetDexClassDefIndex(),
-      *resolved_method->GetDexFile(),
+      *dex_cache->GetDexFile(),
       dex_cache,
       // Read barrier generates a runtime call in slow path and we need a valid
       // dex pc for the associated stack map. 0 is bogus but valid. Bug: 26854537.
index 0127d55..7d343c6 100644 (file)
@@ -70,11 +70,11 @@ class HInliner : public HOptimization {
     SHARED_REQUIRES(Locks::mutator_lock_);
 
   // Create a new HInstanceFieldGet.
-  HInstanceFieldGet* CreateInstanceFieldGet(ArtMethod* resolved_method,
+  HInstanceFieldGet* CreateInstanceFieldGet(Handle<mirror::DexCache> dex_cache,
                                             uint32_t field_index,
                                             HInstruction* obj);
   // Create a new HInstanceFieldSet.
-  HInstanceFieldSet* CreateInstanceFieldSet(ArtMethod* resolved_method,
+  HInstanceFieldSet* CreateInstanceFieldSet(Handle<mirror::DexCache> dex_cache,
                                             uint32_t field_index,
                                             HInstruction* obj,
                                             HInstruction* value);
index a6be324..db39bc8 100644 (file)
@@ -481,6 +481,7 @@ static Intrinsics GetIntrinsic(InlineMethod method) {
     case kInlineOpNonWideConst:
     case kInlineOpIGet:
     case kInlineOpIPut:
+    case kInlineOpConstructor:
       return Intrinsics::kNone;
 
     // String init cases, not intrinsics.
index 1ae2b1b..2849cd8 100644 (file)
@@ -49,6 +49,16 @@ std::ostream& operator<<(std::ostream& os, const DexMemAccessType& type);
 
 // NOTE: The following functions disregard quickened instructions.
 
+// By "direct" const we mean to exclude const-string and const-class
+// which load data from somewhere else, i.e. indirectly.
+constexpr bool IsInstructionDirectConst(Instruction::Code opcode) {
+  return Instruction::CONST_4 <= opcode && opcode <= Instruction::CONST_WIDE_HIGH16;
+}
+
+constexpr bool IsInstructionConstWide(Instruction::Code opcode) {
+  return Instruction::CONST_WIDE_16 <= opcode && opcode <= Instruction::CONST_WIDE_HIGH16;
+}
+
 constexpr bool IsInstructionReturn(Instruction::Code opcode) {
   return Instruction::RETURN_VOID <= opcode && opcode <= Instruction::RETURN_OBJECT;
 }
index 6b84c8f..9b10f2e 100644 (file)
@@ -22,6 +22,7 @@
 #include "dex_file-inl.h"
 #include "dex_instruction.h"
 #include "dex_instruction-inl.h"
+#include "dex_instruction_utils.h"
 #include "mirror/class-inl.h"
 #include "mirror/dex_cache-inl.h"
 #include "verifier/method_verifier-inl.h"
 
 namespace art {
 
+namespace {  // anonymous namespace
+
+// Helper class for matching a pattern.
+class Matcher {
+ public:
+  // Match function type.
+  typedef bool MatchFn(Matcher* matcher);
+
+  template <size_t size>
+  static bool Match(const DexFile::CodeItem* code_item, MatchFn* const (&pattern)[size]);
+
+  // Match and advance.
+
+  static bool Mark(Matcher* matcher);
+
+  template <bool (Matcher::*Fn)()>
+  static bool Required(Matcher* matcher);
+
+  template <bool (Matcher::*Fn)()>
+  static bool Repeated(Matcher* matcher);  // On match, returns to the mark.
+
+  // Match an individual instruction.
+
+  template <Instruction::Code opcode> bool Opcode();
+  bool Const0();
+  bool IPutOnThis();
+
+ private:
+  explicit Matcher(const DexFile::CodeItem* code_item)
+      : code_item_(code_item),
+        instruction_(Instruction::At(code_item->insns_)),
+        pos_(0u),
+        mark_(0u) { }
+
+  static bool DoMatch(const DexFile::CodeItem* code_item, MatchFn* const* pattern, size_t size);
+
+  const DexFile::CodeItem* const code_item_;
+  const Instruction* instruction_;
+  size_t pos_;
+  size_t mark_;
+};
+
+template <size_t size>
+bool Matcher::Match(const DexFile::CodeItem* code_item, MatchFn* const (&pattern)[size]) {
+  return DoMatch(code_item, pattern, size);
+}
+
+bool Matcher::Mark(Matcher* matcher) {
+  matcher->pos_ += 1u;  // Advance to the next match function before marking.
+  matcher->mark_ = matcher->pos_;
+  return true;
+}
+
+template <bool (Matcher::*Fn)()>
+bool Matcher::Required(Matcher* matcher) {
+  if (!(matcher->*Fn)()) {
+    return false;
+  }
+  matcher->pos_ += 1u;
+  matcher->instruction_ = matcher->instruction_->Next();
+  return true;
+}
+
+template <bool (Matcher::*Fn)()>
+bool Matcher::Repeated(Matcher* matcher) {
+  if (!(matcher->*Fn)()) {
+    // Didn't match optional instruction, try the next match function.
+    matcher->pos_ += 1u;
+    return true;
+  }
+  matcher->pos_ = matcher->mark_;
+  matcher->instruction_ = matcher->instruction_->Next();
+  return true;
+}
+
+template <Instruction::Code opcode>
+bool Matcher::Opcode() {
+  return instruction_->Opcode() == opcode;
+}
+
+// Match const 0.
+bool Matcher::Const0() {
+  return IsInstructionDirectConst(instruction_->Opcode()) &&
+      (instruction_->Opcode() == Instruction::CONST_WIDE ? instruction_->VRegB_51l() == 0
+                                                         : instruction_->VRegB() == 0);
+}
+
+bool Matcher::IPutOnThis() {
+  DCHECK_NE(code_item_->ins_size_, 0u);
+  return IsInstructionIPut(instruction_->Opcode()) &&
+      instruction_->VRegB_22c() == code_item_->registers_size_ - code_item_->ins_size_;
+}
+
+bool Matcher::DoMatch(const DexFile::CodeItem* code_item, MatchFn* const* pattern, size_t size) {
+  Matcher matcher(code_item);
+  while (matcher.pos_ != size) {
+    if (!pattern[matcher.pos_](&matcher)) {
+      return false;
+    }
+  }
+  return true;
+}
+
+// Used for a single invoke in a constructor. In that situation, the method verifier makes
+// sure we invoke a constructor either in the same class or superclass with at least "this".
+ArtMethod* GetTargetConstructor(ArtMethod* method, const Instruction* invoke_direct)
+    SHARED_REQUIRES(Locks::mutator_lock_) {
+  DCHECK_EQ(invoke_direct->Opcode(), Instruction::INVOKE_DIRECT);
+  DCHECK_EQ(invoke_direct->VRegC_35c(),
+            method->GetCodeItem()->registers_size_ - method->GetCodeItem()->ins_size_);
+  uint32_t method_index = invoke_direct->VRegB_35c();
+  size_t pointer_size = Runtime::Current()->GetClassLinker()->GetImagePointerSize();
+  ArtMethod* target_method =
+      method->GetDexCache()->GetResolvedMethod(method_index, pointer_size);
+  if (kIsDebugBuild && target_method != nullptr) {
+    CHECK(!target_method->IsStatic());
+    CHECK(target_method->IsConstructor());
+    CHECK(target_method->GetDeclaringClass() == method->GetDeclaringClass() ||
+          target_method->GetDeclaringClass() == method->GetDeclaringClass()->GetSuperClass());
+  }
+  return target_method;
+}
+
+// Return the forwarded arguments and check that all remaining arguments are zero.
+// If the check fails, return static_cast<size_t>(-1).
+size_t CountForwardedConstructorArguments(const DexFile::CodeItem* code_item,
+                                          const Instruction* invoke_direct,
+                                          uint16_t zero_vreg_mask) {
+  DCHECK_EQ(invoke_direct->Opcode(), Instruction::INVOKE_DIRECT);
+  size_t number_of_args = invoke_direct->VRegA_35c();
+  DCHECK_NE(number_of_args, 0u);
+  uint32_t args[Instruction::kMaxVarArgRegs];
+  invoke_direct->GetVarArgs(args);
+  uint16_t this_vreg = args[0];
+  DCHECK_EQ(this_vreg, code_item->registers_size_ - code_item->ins_size_);  // Checked by verifier.
+  size_t forwarded = 1u;
+  while (forwarded < number_of_args &&
+      args[forwarded] == this_vreg + forwarded &&
+      (zero_vreg_mask & (1u << args[forwarded])) == 0) {
+    ++forwarded;
+  }
+  for (size_t i = forwarded; i != number_of_args; ++i) {
+    if ((zero_vreg_mask & (1u << args[i])) == 0) {
+      return static_cast<size_t>(-1);
+    }
+  }
+  return forwarded;
+}
+
+uint16_t GetZeroVRegMask(const Instruction* const0) {
+  DCHECK(IsInstructionDirectConst(const0->Opcode()));
+  DCHECK((const0->Opcode() == Instruction::CONST_WIDE) ? const0->VRegB_51l() == 0u
+                                                       : const0->VRegB() == 0);
+  uint16_t base_mask = IsInstructionConstWide(const0->Opcode()) ? 3u : 1u;
+  return base_mask << const0->VRegA();
+}
+
+// We limit the number of IPUTs storing parameters. There can be any number
+// of IPUTs that store the value 0 as they are useless in a constructor as
+// the object always starts zero-initialized. We also eliminate all but the
+// last store to any field as they are not observable; not even if the field
+// is volatile as no reference to the object can escape from a constructor
+// with this pattern.
+static constexpr size_t kMaxConstructorIPuts = 3u;
+
+struct ConstructorIPutData {
+  ConstructorIPutData() : field_index(DexFile::kDexNoIndex16), arg(0u) { }
+
+  uint16_t field_index;
+  uint16_t arg;
+};
+
+bool RecordConstructorIPut(ArtMethod* method,
+                           const Instruction* new_iput,
+                           uint16_t this_vreg,
+                           uint16_t zero_vreg_mask,
+                           /*inout*/ ConstructorIPutData (&iputs)[kMaxConstructorIPuts])
+    SHARED_REQUIRES(Locks::mutator_lock_) {
+  DCHECK(IsInstructionIPut(new_iput->Opcode()));
+  uint32_t field_index = new_iput->VRegC_22c();
+  size_t pointer_size = Runtime::Current()->GetClassLinker()->GetImagePointerSize();
+  mirror::DexCache* dex_cache = method->GetDexCache();
+  ArtField* field = dex_cache->GetResolvedField(field_index, pointer_size);
+  if (UNLIKELY(field == nullptr)) {
+    return false;
+  }
+  // Remove previous IPUT to the same field, if any. Different field indexes may refer
+  // to the same field, so we need to compare resolved fields from the dex cache.
+  for (size_t old_pos = 0; old_pos != arraysize(iputs); ++old_pos) {
+    if (iputs[old_pos].field_index == DexFile::kDexNoIndex16) {
+      break;
+    }
+    ArtField* f = dex_cache->GetResolvedField(iputs[old_pos].field_index, pointer_size);
+    DCHECK(f != nullptr);
+    if (f == field) {
+      auto back_it = std::copy(iputs + old_pos + 1, iputs + arraysize(iputs), iputs + old_pos);
+      *back_it = ConstructorIPutData();
+      break;
+    }
+  }
+  // If the stored value isn't zero, record the IPUT.
+  if ((zero_vreg_mask & (1u << new_iput->VRegA_22c())) == 0u) {
+    size_t new_pos = 0;
+    while (new_pos != arraysize(iputs) && iputs[new_pos].field_index != DexFile::kDexNoIndex16) {
+      ++new_pos;
+    }
+    if (new_pos == arraysize(iputs)) {
+      return false;  // Exceeded capacity of the output array.
+    }
+    iputs[new_pos].field_index = field_index;
+    iputs[new_pos].arg = new_iput->VRegA_22c() - this_vreg;
+  }
+  return true;
+}
+
+bool DoAnalyseConstructor(const DexFile::CodeItem* code_item,
+                          ArtMethod* method,
+                          /*inout*/ ConstructorIPutData (&iputs)[kMaxConstructorIPuts])
+    SHARED_REQUIRES(Locks::mutator_lock_) {
+  // On entry we should not have any IPUTs yet.
+  DCHECK_EQ(0, std::count_if(
+      iputs,
+      iputs + arraysize(iputs),
+      [](const ConstructorIPutData& iput_data) {
+        return iput_data.field_index != DexFile::kDexNoIndex16;
+      }));
+
+  // Limit the maximum number of code units we're willing to match.
+  static constexpr size_t kMaxCodeUnits = 16u;
+
+  // Limit the number of registers that the constructor may use to 16.
+  // Given that IPUTs must use low 16 registers and we do not match MOVEs,
+  // this is a reasonable limitation.
+  static constexpr size_t kMaxVRegs = 16u;
+
+  // We try to match a constructor that calls another constructor (either in
+  // superclass or in the same class) with the same parameters, or with some
+  // parameters truncated (allowed only for calls to superclass constructor)
+  // or with extra parameters with value 0 (with any type, including null).
+  // This call can be followed by optional IPUTs on "this" storing either one
+  // of the parameters or 0 and the code must then finish with RETURN_VOID.
+  // The called constructor must be either java.lang.Object.<init>() or it
+  // must also match the same pattern.
+  static Matcher::MatchFn* const kConstructorPattern[] = {
+      &Matcher::Mark,
+      &Matcher::Repeated<&Matcher::Const0>,
+      &Matcher::Required<&Matcher::Opcode<Instruction::INVOKE_DIRECT>>,
+      &Matcher::Mark,
+      &Matcher::Repeated<&Matcher::Const0>,
+      &Matcher::Repeated<&Matcher::IPutOnThis>,
+      &Matcher::Required<&Matcher::Opcode<Instruction::RETURN_VOID>>,
+  };
+
+  DCHECK(method != nullptr);
+  DCHECK(!method->IsStatic());
+  DCHECK(method->IsConstructor());
+  DCHECK(code_item != nullptr);
+  if (!method->GetDeclaringClass()->IsVerified() ||
+      code_item->insns_size_in_code_units_ > kMaxCodeUnits ||
+      code_item->registers_size_ > kMaxVRegs ||
+      !Matcher::Match(code_item, kConstructorPattern)) {
+    return false;
+  }
+
+  // Verify the invoke, prevent a few odd cases and collect IPUTs.
+  uint16_t this_vreg = code_item->registers_size_ - code_item->ins_size_;
+  uint16_t zero_vreg_mask = 0u;
+  for (const Instruction* instruction = Instruction::At(code_item->insns_);
+      instruction->Opcode() != Instruction::RETURN_VOID;
+      instruction = instruction->Next()) {
+    if (instruction->Opcode() == Instruction::INVOKE_DIRECT) {
+      ArtMethod* target_method = GetTargetConstructor(method, instruction);
+      if (target_method == nullptr) {
+        return false;
+      }
+      // We allow forwarding constructors only if they pass more arguments
+      // to prevent infinite recursion.
+      if (target_method->GetDeclaringClass() == method->GetDeclaringClass() &&
+          instruction->VRegA_35c() <= code_item->ins_size_) {
+        return false;
+      }
+      size_t forwarded = CountForwardedConstructorArguments(code_item, instruction, zero_vreg_mask);
+      if (forwarded == static_cast<size_t>(-1)) {
+        return false;
+      }
+      if (target_method->GetDeclaringClass()->IsObjectClass()) {
+        DCHECK_EQ(Instruction::At(target_method->GetCodeItem()->insns_)->Opcode(),
+                  Instruction::RETURN_VOID);
+      } else {
+        const DexFile::CodeItem* target_code_item = target_method->GetCodeItem();
+        if (target_code_item == nullptr) {
+          return false;  // Native constructor?
+        }
+        if (!DoAnalyseConstructor(target_code_item, target_method, iputs)) {
+          return false;
+        }
+        // Prune IPUTs with zero input.
+        auto kept_end = std::remove_if(
+            iputs,
+            iputs + arraysize(iputs),
+            [forwarded](const ConstructorIPutData& iput_data) {
+              return iput_data.arg >= forwarded;
+            });
+        std::fill(kept_end, iputs + arraysize(iputs), ConstructorIPutData());
+        // If we have any IPUTs from the call, check that the target method is in the same
+        // dex file (compare DexCache references), otherwise field_indexes would be bogus.
+        if (iputs[0].field_index != DexFile::kDexNoIndex16 &&
+            target_method->GetDexCache() != method->GetDexCache()) {
+          return false;
+        }
+      }
+    } else if (IsInstructionDirectConst(instruction->Opcode())) {
+      zero_vreg_mask |= GetZeroVRegMask(instruction);
+      if ((zero_vreg_mask & (1u << this_vreg)) != 0u) {
+        return false;  // Overwriting `this` is unsupported.
+      }
+    } else {
+      DCHECK(IsInstructionIPut(instruction->Opcode()));
+      DCHECK_EQ(instruction->VRegB_22c(), this_vreg);
+      if (!RecordConstructorIPut(method, instruction, this_vreg, zero_vreg_mask, iputs)) {
+        return false;
+      }
+    }
+  }
+  return true;
+}
+
+}  // anonymous namespace
+
+bool AnalyseConstructor(const DexFile::CodeItem* code_item,
+                        ArtMethod* method,
+                        InlineMethod* result)
+    SHARED_REQUIRES(Locks::mutator_lock_) {
+  ConstructorIPutData iputs[kMaxConstructorIPuts];
+  if (!DoAnalyseConstructor(code_item, method, iputs)) {
+    return false;
+  }
+  static_assert(kMaxConstructorIPuts == 3, "Unexpected limit");  // Code below depends on this.
+  DCHECK(iputs[0].field_index != DexFile::kDexNoIndex16 ||
+         iputs[1].field_index == DexFile::kDexNoIndex16);
+  DCHECK(iputs[1].field_index != DexFile::kDexNoIndex16 ||
+         iputs[2].field_index == DexFile::kDexNoIndex16);
+
+#define STORE_IPUT(n)                                                         \
+  do {                                                                        \
+    result->d.constructor_data.iput##n##_field_index = iputs[n].field_index;  \
+    result->d.constructor_data.iput##n##_arg = iputs[n].arg;                  \
+  } while (false)
+
+  STORE_IPUT(0);
+  STORE_IPUT(1);
+  STORE_IPUT(2);
+#undef STORE_IPUT
+
+  result->opcode = kInlineOpConstructor;
+  result->flags = kInlineSpecial;
+  result->d.constructor_data.reserved = 0u;
+  return true;
+}
+
 static_assert(InlineMethodAnalyser::IsInstructionIGet(Instruction::IGET), "iget type");
 static_assert(InlineMethodAnalyser::IsInstructionIGet(Instruction::IGET_WIDE), "iget_wide type");
 static_assert(InlineMethodAnalyser::IsInstructionIGet(Instruction::IGET_OBJECT),
@@ -123,7 +484,19 @@ bool InlineMethodAnalyser::AnalyseMethodCode(const DexFile::CodeItem* code_item,
     case Instruction::CONST_16:
     case Instruction::CONST_HIGH16:
       // TODO: Support wide constants (RETURN_WIDE).
-      return AnalyseConstMethod(code_item, result);
+      if (AnalyseConstMethod(code_item, result)) {
+        return true;
+      }
+      FALLTHROUGH_INTENDED;
+    case Instruction::CONST_WIDE:
+    case Instruction::CONST_WIDE_16:
+    case Instruction::CONST_WIDE_32:
+    case Instruction::CONST_WIDE_HIGH16:
+    case Instruction::INVOKE_DIRECT:
+      if (method != nullptr && !method->IsStatic() && method->IsConstructor()) {
+        return AnalyseConstructor(code_item, method, result);
+      }
+      return false;
     case Instruction::IGET:
     case Instruction::IGET_OBJECT:
     case Instruction::IGET_BOOLEAN:
index 046d225..0b09a70 100644 (file)
@@ -107,6 +107,7 @@ enum InlineMethodOpcode : uint16_t {
   kInlineOpNonWideConst,
   kInlineOpIGet,
   kInlineOpIPut,
+  kInlineOpConstructor,
   kInlineStringInit,
 };
 std::ostream& operator<<(std::ostream& os, const InlineMethodOpcode& rhs);
@@ -168,6 +169,19 @@ struct InlineReturnArgData {
 static_assert(sizeof(InlineReturnArgData) == sizeof(uint64_t),
               "Invalid size of InlineReturnArgData");
 
+struct InlineConstructorData {
+  // There can be up to 3 IPUTs, unused fields are marked with kNoDexIndex16.
+  uint16_t iput0_field_index;
+  uint16_t iput1_field_index;
+  uint16_t iput2_field_index;
+  uint16_t iput0_arg : 4;
+  uint16_t iput1_arg : 4;
+  uint16_t iput2_arg : 4;
+  uint16_t reserved : 4;
+};
+static_assert(sizeof(InlineConstructorData) == sizeof(uint64_t),
+              "Invalid size of InlineConstructorData");
+
 struct InlineMethod {
   InlineMethodOpcode opcode;
   InlineMethodFlags flags;
@@ -175,6 +189,7 @@ struct InlineMethod {
     uint64_t data;
     InlineIGetIPutData ifield_data;
     InlineReturnArgData return_data;
+    InlineConstructorData constructor_data;
   } d;
 };
 
diff --git a/test/569-checker-pattern-replacement/src-multidex/Base.java b/test/569-checker-pattern-replacement/src-multidex/Base.java
new file mode 100644 (file)
index 0000000..f4d59af
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+public class Base {
+  Base() {
+    intField = 0;               // Unnecessary IPUT.
+    doubleField = 0.0;          // Unnecessary IPUT.
+    objectField = null;         // Unnecessary IPUT.
+  }
+
+  Base(int intValue) {
+    intField = intValue;
+  }
+
+  Base(String stringValue) {
+    objectField = stringValue;  // Unnecessary IPUT.
+    stringField = stringValue;
+    objectField = null;         // Unnecessary IPUT.
+  }
+
+  Base(double doubleValue, Object objectValue) {
+    doubleField = doubleValue;
+    objectField = objectValue;
+  }
+
+  Base(int intValue, double doubleValue, Object objectValue) {
+    intField = intValue;
+    doubleField = doubleValue;
+    objectField = objectValue;
+  }
+
+  Base(int intValue, double doubleValue, Object objectValue, String stringValue) {
+    // Outside our limit of 3 IPUTs.
+    intField = intValue;
+    doubleField = doubleValue;
+    objectField = objectValue;
+    stringField = stringValue;
+  }
+
+  Base(double doubleValue) {
+    this(doubleValue, null);
+  }
+
+  Base(Object objectValue) {
+    // Unsupported forwarding of a value after a zero.
+    this(0.0, objectValue);
+  }
+
+  Base(int intValue, long dummy) {
+    this(intValue, 0.0, null);
+  }
+
+  public int intField;
+  public double doubleField;
+  public Object objectField;
+  public String stringField;
+}
diff --git a/test/569-checker-pattern-replacement/src-multidex/BaseWithFinalField.java b/test/569-checker-pattern-replacement/src-multidex/BaseWithFinalField.java
new file mode 100644 (file)
index 0000000..7a1d591
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+public class BaseWithFinalField {
+  BaseWithFinalField() {
+    intField = 0;
+  }
+
+  BaseWithFinalField(int intValue) {
+    intField = intValue;
+  }
+
+  public final int intField;
+}
diff --git a/test/569-checker-pattern-replacement/src-multidex/Derived.java b/test/569-checker-pattern-replacement/src-multidex/Derived.java
new file mode 100644 (file)
index 0000000..184563f
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+public final class Derived extends Base {
+  public Derived() {
+    this(0);
+  }
+
+  public Derived(int intValue) {
+    super(intValue);
+  }
+
+  public Derived(String stringValue) {
+    super(stringValue);
+    stringField = null;   // Clear field set by Base.<init>(String).
+  }
+
+  public Derived(double doubleValue) {
+    super(doubleValue, null);
+  }
+
+  public Derived(int intValue, double doubleValue, Object objectValue) {
+    super(intValue, doubleValue, objectValue);
+    objectField = null;   // Clear field set by Base.<init>(int, double, Object).
+    intField = 0;         // Clear field set by Base.<init>(int, double, Object).
+  }
+
+  Derived(int intValue, double doubleValue, Object objectValue, String stringValue) {
+    super(intValue, doubleValue, objectValue, stringValue);
+    // Clearing fields here doesn't help because the superclass constructor must
+    // satisfy the pattern constraints on its own and it doesn't (it has 4 IPUTs).
+    intField = 0;
+    doubleField = 0.0;
+    objectField = null;
+    stringField = null;
+  }
+
+  public Derived(float floatValue) {
+    super();
+    floatField = floatValue;
+  }
+
+  public Derived(int intValue, double doubleValue, Object objectValue, float floatValue) {
+    super(intValue, doubleValue, objectValue);
+    objectField = null;   // Clear field set by Base.<init>(int, double, Object).
+    floatField = floatValue;
+  }
+
+  public float floatField;
+}
diff --git a/test/569-checker-pattern-replacement/src-multidex/DerivedInSecondDex.java b/test/569-checker-pattern-replacement/src-multidex/DerivedInSecondDex.java
new file mode 100644 (file)
index 0000000..50266e8
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+public final class DerivedInSecondDex extends BaseInMainDex {
+  DerivedInSecondDex() {
+    super();
+  }
+
+  DerivedInSecondDex(int intValue) {
+    // Not matched: Superclass in a different dex file has an IPUT.
+    super(intValue);
+  }
+
+  DerivedInSecondDex(long dummy) {
+    // Matched: Superclass in a different dex file has an IPUT that's pruned because we store 0.
+    super(0);
+  }
+}
diff --git a/test/569-checker-pattern-replacement/src-multidex/DerivedWithFinalField.java b/test/569-checker-pattern-replacement/src-multidex/DerivedWithFinalField.java
new file mode 100644 (file)
index 0000000..5b39b8a
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+public final class DerivedWithFinalField extends BaseWithFinalField {
+  DerivedWithFinalField() {
+    this(0);
+  }
+
+  DerivedWithFinalField(int intValue) {
+    super(intValue);
+    doubleField = 0.0;
+  }
+
+  DerivedWithFinalField(double doubleValue) {
+    super(0);
+    doubleField = doubleValue;
+  }
+
+  DerivedWithFinalField(int intValue, double doubleValue) {
+    super(intValue);
+    doubleField = doubleValue;
+  }
+
+  public final double doubleField;
+}
diff --git a/test/569-checker-pattern-replacement/src/BaseInMainDex.java b/test/569-checker-pattern-replacement/src/BaseInMainDex.java
new file mode 100644 (file)
index 0000000..b401540
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+public class BaseInMainDex {
+  BaseInMainDex() {
+  }
+
+  BaseInMainDex(int intValue) {
+    intField = intValue;
+  }
+
+  public int intField;
+}
index e2d451c..345e9fd 100644 (file)
  */
 
 public class Main {
-    /// CHECK-START: void Main.staticNop() inliner (before)
-    /// CHECK:                          InvokeStaticOrDirect
+  /// CHECK-START: void Main.staticNop() inliner (before)
+  /// CHECK:                          InvokeStaticOrDirect
 
-    /// CHECK-START: void Main.staticNop() inliner (after)
-    /// CHECK-NOT:                      InvokeStaticOrDirect
+  /// CHECK-START: void Main.staticNop() inliner (after)
+  /// CHECK-NOT:                      InvokeStaticOrDirect
 
-    public static void staticNop() {
-      Second.staticNop(11);
-    }
-
-    /// CHECK-START: void Main.nop(Second) inliner (before)
-    /// CHECK:                          InvokeVirtual
-
-    /// CHECK-START: void Main.nop(Second) inliner (after)
-    /// CHECK-NOT:                      InvokeVirtual
-
-    public static void nop(Second s) {
-      s.nop();
-    }
-
-    /// CHECK-START: java.lang.Object Main.staticReturnArg2(java.lang.String) inliner (before)
-    /// CHECK-DAG:  <<Value:l\d+>>      ParameterValue
-    /// CHECK-DAG:  <<Ignored:i\d+>>    IntConstant 77
-    /// CHECK-DAG:  <<ClinitCk:l\d+>>   ClinitCheck
-    // Note: The ArtMethod* (typed as int or long) is optional after sharpening.
-    /// CHECK-DAG:  <<Invoke:l\d+>>     InvokeStaticOrDirect [<<Ignored>>,<<Value>>{{(,[ij]\d+)?}},<<ClinitCk>>]
-    /// CHECK-DAG:                      Return [<<Invoke>>]
+  public static void staticNop() {
+    Second.staticNop(11);
+  }
 
-    /// CHECK-START: java.lang.Object Main.staticReturnArg2(java.lang.String) inliner (after)
-    /// CHECK-DAG:  <<Value:l\d+>>      ParameterValue
-    /// CHECK-DAG:                      Return [<<Value>>]
+  /// CHECK-START: void Main.nop(Second) inliner (before)
+  /// CHECK:                          InvokeVirtual
 
-    /// CHECK-START: java.lang.Object Main.staticReturnArg2(java.lang.String) inliner (after)
-    /// CHECK-NOT:                      InvokeStaticOrDirect
+  /// CHECK-START: void Main.nop(Second) inliner (after)
+  /// CHECK-NOT:                      InvokeVirtual
 
-    public static Object staticReturnArg2(String value) {
-      return Second.staticReturnArg2(77, value);
-    }
+  public static void nop(Second s) {
+    s.nop();
+  }
 
-    /// CHECK-START: long Main.returnArg1(Second, long) inliner (before)
-    /// CHECK-DAG:  <<Second:l\d+>>     ParameterValue
-    /// CHECK-DAG:  <<Value:j\d+>>      ParameterValue
-    /// CHECK-DAG:  <<NullCk:l\d+>>     NullCheck [<<Second>>]
-    /// CHECK-DAG:  <<Invoke:j\d+>>     InvokeVirtual [<<NullCk>>,<<Value>>]
-    /// CHECK-DAG:                      Return [<<Invoke>>]
+  /// CHECK-START: java.lang.Object Main.staticReturnArg2(java.lang.String) inliner (before)
+  /// CHECK-DAG:  <<Value:l\d+>>      ParameterValue
+  /// CHECK-DAG:  <<Ignored:i\d+>>    IntConstant 77
+  /// CHECK-DAG:  <<ClinitCk:l\d+>>   ClinitCheck
+  // Note: The ArtMethod* (typed as int or long) is optional after sharpening.
+  /// CHECK-DAG:  <<Invoke:l\d+>>     InvokeStaticOrDirect [<<Ignored>>,<<Value>>{{(,[ij]\d+)?}},<<ClinitCk>>]
+  /// CHECK-DAG:                      Return [<<Invoke>>]
 
-    /// CHECK-START: long Main.returnArg1(Second, long) inliner (after)
-    /// CHECK-DAG:  <<Value:j\d+>>      ParameterValue
-    /// CHECK-DAG:                      Return [<<Value>>]
+  /// CHECK-START: java.lang.Object Main.staticReturnArg2(java.lang.String) inliner (after)
+  /// CHECK-DAG:  <<Value:l\d+>>      ParameterValue
+  /// CHECK-DAG:                      Return [<<Value>>]
 
-    /// CHECK-START: long Main.returnArg1(Second, long) inliner (after)
-    /// CHECK-NOT:                      InvokeVirtual
+  /// CHECK-START: java.lang.Object Main.staticReturnArg2(java.lang.String) inliner (after)
+  /// CHECK-NOT:                      InvokeStaticOrDirect
 
-    public static long returnArg1(Second s, long value) {
-      return s.returnArg1(value);
-    }
+  public static Object staticReturnArg2(String value) {
+    return Second.staticReturnArg2(77, value);
+  }
 
-    /// CHECK-START: int Main.staticReturn9() inliner (before)
-    /// CHECK:      {{i\d+}}            InvokeStaticOrDirect
+  /// CHECK-START: long Main.returnArg1(Second, long) inliner (before)
+  /// CHECK-DAG:  <<Second:l\d+>>     ParameterValue
+  /// CHECK-DAG:  <<Value:j\d+>>      ParameterValue
+  /// CHECK-DAG:  <<NullCk:l\d+>>     NullCheck [<<Second>>]
+  /// CHECK-DAG:  <<Invoke:j\d+>>     InvokeVirtual [<<NullCk>>,<<Value>>]
+  /// CHECK-DAG:                      Return [<<Invoke>>]
 
-    /// CHECK-START: int Main.staticReturn9() inliner (before)
-    /// CHECK-NOT:                      IntConstant 9
+  /// CHECK-START: long Main.returnArg1(Second, long) inliner (after)
+  /// CHECK-DAG:  <<Value:j\d+>>      ParameterValue
+  /// CHECK-DAG:                      Return [<<Value>>]
 
-    /// CHECK-START: int Main.staticReturn9() inliner (after)
-    /// CHECK-DAG:  <<Const9:i\d+>>     IntConstant 9
-    /// CHECK-DAG:                      Return [<<Const9>>]
+  /// CHECK-START: long Main.returnArg1(Second, long) inliner (after)
+  /// CHECK-NOT:                      InvokeVirtual
 
-    /// CHECK-START: int Main.staticReturn9() inliner (after)
-    /// CHECK-NOT:                      InvokeStaticOrDirect
+  public static long returnArg1(Second s, long value) {
+    return s.returnArg1(value);
+  }
 
-    public static int staticReturn9() {
-      return Second.staticReturn9();
-    }
-
-    /// CHECK-START: int Main.return7(Second) inliner (before)
-    /// CHECK:      {{i\d+}}            InvokeVirtual
-
-    /// CHECK-START: int Main.return7(Second) inliner (before)
-    /// CHECK-NOT:                      IntConstant 7
-
-    /// CHECK-START: int Main.return7(Second) inliner (after)
-    /// CHECK-DAG:  <<Const7:i\d+>>     IntConstant 7
-    /// CHECK-DAG:                      Return [<<Const7>>]
-
-    /// CHECK-START: int Main.return7(Second) inliner (after)
-    /// CHECK-NOT:                      InvokeVirtual
-
-    public static int return7(Second s) {
-      return s.return7(null);
-    }
+  /// CHECK-START: int Main.staticReturn9() inliner (before)
+  /// CHECK:      {{i\d+}}            InvokeStaticOrDirect
 
-    /// CHECK-START: java.lang.String Main.staticReturnNull() inliner (before)
-    /// CHECK:      {{l\d+}}            InvokeStaticOrDirect
+  /// CHECK-START: int Main.staticReturn9() inliner (before)
+  /// CHECK-NOT:                      IntConstant 9
 
-    /// CHECK-START: java.lang.String Main.staticReturnNull() inliner (before)
-    /// CHECK-NOT:                      NullConstant
+  /// CHECK-START: int Main.staticReturn9() inliner (after)
+  /// CHECK-DAG:  <<Const9:i\d+>>     IntConstant 9
+  /// CHECK-DAG:                      Return [<<Const9>>]
 
-    /// CHECK-START: java.lang.String Main.staticReturnNull() inliner (after)
-    /// CHECK-DAG:  <<Null:l\d+>>       NullConstant
-    /// CHECK-DAG:                      Return [<<Null>>]
+  /// CHECK-START: int Main.staticReturn9() inliner (after)
+  /// CHECK-NOT:                      InvokeStaticOrDirect
 
-    /// CHECK-START: java.lang.String Main.staticReturnNull() inliner (after)
-    /// CHECK-NOT:                      InvokeStaticOrDirect
+  public static int staticReturn9() {
+    return Second.staticReturn9();
+  }
 
-    public static String staticReturnNull() {
-      return Second.staticReturnNull();
-    }
+  /// CHECK-START: int Main.return7(Second) inliner (before)
+  /// CHECK:      {{i\d+}}            InvokeVirtual
 
-    /// CHECK-START: java.lang.Object Main.returnNull(Second) inliner (before)
-    /// CHECK:      {{l\d+}}            InvokeVirtual
+  /// CHECK-START: int Main.return7(Second) inliner (before)
+  /// CHECK-NOT:                      IntConstant 7
 
-    /// CHECK-START: java.lang.Object Main.returnNull(Second) inliner (before)
-    /// CHECK-NOT:                      NullConstant
+  /// CHECK-START: int Main.return7(Second) inliner (after)
+  /// CHECK-DAG:  <<Const7:i\d+>>     IntConstant 7
+  /// CHECK-DAG:                      Return [<<Const7>>]
 
-    /// CHECK-START: java.lang.Object Main.returnNull(Second) inliner (after)
-    /// CHECK-DAG:  <<Null:l\d+>>       NullConstant
-    /// CHECK-DAG:                      Return [<<Null>>]
+  /// CHECK-START: int Main.return7(Second) inliner (after)
+  /// CHECK-NOT:                      InvokeVirtual
 
-    /// CHECK-START: java.lang.Object Main.returnNull(Second) inliner (after)
-    /// CHECK-NOT:                      InvokeVirtual
+  public static int return7(Second s) {
+    return s.return7(null);
+  }
 
-    public static Object returnNull(Second s) {
-      return s.returnNull();
-    }
+  /// CHECK-START: java.lang.String Main.staticReturnNull() inliner (before)
+  /// CHECK:      {{l\d+}}            InvokeStaticOrDirect
 
-    /// CHECK-START: int Main.getInt(Second) inliner (before)
-    /// CHECK:      {{i\d+}}            InvokeVirtual
+  /// CHECK-START: java.lang.String Main.staticReturnNull() inliner (before)
+  /// CHECK-NOT:                      NullConstant
 
-    /// CHECK-START: int Main.getInt(Second) inliner (after)
-    /// CHECK:      {{i\d+}}            InstanceFieldGet
+  /// CHECK-START: java.lang.String Main.staticReturnNull() inliner (after)
+  /// CHECK-DAG:  <<Null:l\d+>>       NullConstant
+  /// CHECK-DAG:                      Return [<<Null>>]
 
-    /// CHECK-START: int Main.getInt(Second) inliner (after)
-    /// CHECK-NOT:                      InvokeVirtual
+  /// CHECK-START: java.lang.String Main.staticReturnNull() inliner (after)
+  /// CHECK-NOT:                      InvokeStaticOrDirect
 
-    public static int getInt(Second s) {
-      return s.getInstanceIntField();
-    }
+  public static String staticReturnNull() {
+    return Second.staticReturnNull();
+  }
 
-    /// CHECK-START: double Main.getDouble(Second) inliner (before)
-    /// CHECK:      {{d\d+}}            InvokeVirtual
+  /// CHECK-START: java.lang.Object Main.returnNull(Second) inliner (before)
+  /// CHECK:      {{l\d+}}            InvokeVirtual
 
-    /// CHECK-START: double Main.getDouble(Second) inliner (after)
-    /// CHECK:      {{d\d+}}            InstanceFieldGet
+  /// CHECK-START: java.lang.Object Main.returnNull(Second) inliner (before)
+  /// CHECK-NOT:                      NullConstant
 
-    /// CHECK-START: double Main.getDouble(Second) inliner (after)
-    /// CHECK-NOT:                      InvokeVirtual
+  /// CHECK-START: java.lang.Object Main.returnNull(Second) inliner (after)
+  /// CHECK-DAG:  <<Null:l\d+>>       NullConstant
+  /// CHECK-DAG:                      Return [<<Null>>]
 
-    public static double getDouble(Second s) {
-      return s.getInstanceDoubleField(22);
-    }
+  /// CHECK-START: java.lang.Object Main.returnNull(Second) inliner (after)
+  /// CHECK-NOT:                      InvokeVirtual
 
-    /// CHECK-START: java.lang.Object Main.getObject(Second) inliner (before)
-    /// CHECK:      {{l\d+}}            InvokeVirtual
+  public static Object returnNull(Second s) {
+    return s.returnNull();
+  }
 
-    /// CHECK-START: java.lang.Object Main.getObject(Second) inliner (after)
-    /// CHECK:      {{l\d+}}            InstanceFieldGet
+  /// CHECK-START: int Main.getInt(Second) inliner (before)
+  /// CHECK:      {{i\d+}}            InvokeVirtual
 
-    /// CHECK-START: java.lang.Object Main.getObject(Second) inliner (after)
-    /// CHECK-NOT:                      InvokeVirtual
+  /// CHECK-START: int Main.getInt(Second) inliner (after)
+  /// CHECK:      {{i\d+}}            InstanceFieldGet
 
-    public static Object getObject(Second s) {
-      return s.getInstanceObjectField(-1L);
-    }
+  /// CHECK-START: int Main.getInt(Second) inliner (after)
+  /// CHECK-NOT:                      InvokeVirtual
 
-    /// CHECK-START: java.lang.String Main.getString(Second) inliner (before)
-    /// CHECK:      {{l\d+}}            InvokeVirtual
+  public static int getInt(Second s) {
+    return s.getInstanceIntField();
+  }
 
-    /// CHECK-START: java.lang.String Main.getString(Second) inliner (after)
-    /// CHECK:      {{l\d+}}            InstanceFieldGet
+  /// CHECK-START: double Main.getDouble(Second) inliner (before)
+  /// CHECK:      {{d\d+}}            InvokeVirtual
 
-    /// CHECK-START: java.lang.String Main.getString(Second) inliner (after)
-    /// CHECK-NOT:                      InvokeVirtual
+  /// CHECK-START: double Main.getDouble(Second) inliner (after)
+  /// CHECK:      {{d\d+}}            InstanceFieldGet
 
-    public static String getString(Second s) {
-      return s.getInstanceStringField(null, "whatever", 1234L);
-    }
+  /// CHECK-START: double Main.getDouble(Second) inliner (after)
+  /// CHECK-NOT:                      InvokeVirtual
 
-    /// CHECK-START: int Main.staticGetInt(Second) inliner (before)
-    /// CHECK:      {{i\d+}}            InvokeStaticOrDirect
+  public static double getDouble(Second s) {
+    return s.getInstanceDoubleField(22);
+  }
 
-    /// CHECK-START: int Main.staticGetInt(Second) inliner (after)
-    /// CHECK:      {{i\d+}}            InvokeStaticOrDirect
+  /// CHECK-START: java.lang.Object Main.getObject(Second) inliner (before)
+  /// CHECK:      {{l\d+}}            InvokeVirtual
 
-    /// CHECK-START: int Main.staticGetInt(Second) inliner (after)
-    /// CHECK-NOT:                      InstanceFieldGet
+  /// CHECK-START: java.lang.Object Main.getObject(Second) inliner (after)
+  /// CHECK:      {{l\d+}}            InstanceFieldGet
 
-    public static int staticGetInt(Second s) {
-      return Second.staticGetInstanceIntField(s);
-    }
+  /// CHECK-START: java.lang.Object Main.getObject(Second) inliner (after)
+  /// CHECK-NOT:                      InvokeVirtual
 
-    /// CHECK-START: double Main.getDoubleFromParam(Second) inliner (before)
-    /// CHECK:      {{d\d+}}            InvokeVirtual
+  public static Object getObject(Second s) {
+    return s.getInstanceObjectField(-1L);
+  }
 
-    /// CHECK-START: double Main.getDoubleFromParam(Second) inliner (after)
-    /// CHECK:      {{d\d+}}            InvokeVirtual
+  /// CHECK-START: java.lang.String Main.getString(Second) inliner (before)
+  /// CHECK:      {{l\d+}}            InvokeVirtual
 
-    /// CHECK-START: double Main.getDoubleFromParam(Second) inliner (after)
-    /// CHECK-NOT:                      InstanceFieldGet
+  /// CHECK-START: java.lang.String Main.getString(Second) inliner (after)
+  /// CHECK:      {{l\d+}}            InstanceFieldGet
 
-    public static double getDoubleFromParam(Second s) {
-      return s.getInstanceDoubleFieldFromParam(s);
-    }
+  /// CHECK-START: java.lang.String Main.getString(Second) inliner (after)
+  /// CHECK-NOT:                      InvokeVirtual
 
-    /// CHECK-START: int Main.getStaticInt(Second) inliner (before)
-    /// CHECK:      {{i\d+}}            InvokeVirtual
+  public static String getString(Second s) {
+    return s.getInstanceStringField(null, "whatever", 1234L);
+  }
 
-    /// CHECK-START: int Main.getStaticInt(Second) inliner (after)
-    /// CHECK:      {{i\d+}}            InvokeVirtual
+  /// CHECK-START: int Main.staticGetInt(Second) inliner (before)
+  /// CHECK:      {{i\d+}}            InvokeStaticOrDirect
 
-    /// CHECK-START: int Main.getStaticInt(Second) inliner (after)
-    /// CHECK-NOT:                      InstanceFieldGet
-    /// CHECK-NOT:                      StaticFieldGet
+  /// CHECK-START: int Main.staticGetInt(Second) inliner (after)
+  /// CHECK:      {{i\d+}}            InvokeStaticOrDirect
 
-    public static int getStaticInt(Second s) {
-      return s.getStaticIntField();
-    }
+  /// CHECK-START: int Main.staticGetInt(Second) inliner (after)
+  /// CHECK-NOT:                      InstanceFieldGet
 
-    /// CHECK-START: long Main.setLong(Second, long) inliner (before)
-    /// CHECK:                          InvokeVirtual
+  public static int staticGetInt(Second s) {
+    return Second.staticGetInstanceIntField(s);
+  }
 
-    /// CHECK-START: long Main.setLong(Second, long) inliner (after)
-    /// CHECK:                          InstanceFieldSet
+  /// CHECK-START: double Main.getDoubleFromParam(Second) inliner (before)
+  /// CHECK:      {{d\d+}}            InvokeVirtual
 
-    /// CHECK-START: long Main.setLong(Second, long) inliner (after)
-    /// CHECK-NOT:                      InvokeVirtual
+  /// CHECK-START: double Main.getDoubleFromParam(Second) inliner (after)
+  /// CHECK:      {{d\d+}}            InvokeVirtual
 
-    public static long setLong(Second s, long value) {
-      s.setInstanceLongField(-1, value);
-      return s.instanceLongField;
-    }
+  /// CHECK-START: double Main.getDoubleFromParam(Second) inliner (after)
+  /// CHECK-NOT:                      InstanceFieldGet
 
-    /// CHECK-START: long Main.setLongReturnArg2(Second, long, int) inliner (before)
-    /// CHECK:                          InvokeVirtual
-
-    /// CHECK-START: long Main.setLongReturnArg2(Second, long, int) inliner (after)
-    /// CHECK-DAG:  <<Second:l\d+>>     ParameterValue
-    /// CHECK-DAG:  <<Value:j\d+>>      ParameterValue
-    /// CHECK-DAG:  <<Arg2:i\d+>>       ParameterValue
-    /// CHECK-DAG:  <<NullCk:l\d+>>     NullCheck [<<Second>>]
-    /// CHECK-DAG:                      InstanceFieldSet [<<NullCk>>,<<Value>>]
-    /// CHECK-DAG:  <<NullCk2:l\d+>>    NullCheck [<<Second>>]
-    /// CHECK-DAG:  <<IGet:j\d+>>       InstanceFieldGet [<<NullCk2>>]
-    /// CHECK-DAG:  <<Conv:j\d+>>       TypeConversion [<<Arg2>>]
-    /// CHECK-DAG:  <<Add:j\d+>>        Add [<<IGet>>,<<Conv>>]
-    /// CHECK-DAG:                      Return [<<Add>>]
-
-    /// CHECK-START: long Main.setLongReturnArg2(Second, long, int) inliner (after)
-    /// CHECK-NOT:                      InvokeVirtual
-
-    public static long setLongReturnArg2(Second s, long value, int arg2) {
-      int result = s.setInstanceLongFieldReturnArg2(value, arg2);
-      return s.instanceLongField + result;
-    }
+  public static double getDoubleFromParam(Second s) {
+    return s.getInstanceDoubleFieldFromParam(s);
+  }
 
-    /// CHECK-START: long Main.staticSetLong(Second, long) inliner (before)
-    /// CHECK:                          InvokeStaticOrDirect
+  /// CHECK-START: int Main.getStaticInt(Second) inliner (before)
+  /// CHECK:      {{i\d+}}            InvokeVirtual
 
-    /// CHECK-START: long Main.staticSetLong(Second, long) inliner (after)
-    /// CHECK:                          InvokeStaticOrDirect
+  /// CHECK-START: int Main.getStaticInt(Second) inliner (after)
+  /// CHECK:      {{i\d+}}            InvokeVirtual
 
-    /// CHECK-START: long Main.staticSetLong(Second, long) inliner (after)
-    /// CHECK-NOT:                      InstanceFieldSet
+  /// CHECK-START: int Main.getStaticInt(Second) inliner (after)
+  /// CHECK-NOT:                      InstanceFieldGet
+  /// CHECK-NOT:                      StaticFieldGet
 
-    public static long staticSetLong(Second s, long value) {
-      Second.staticSetInstanceLongField(s, value);
-      return s.instanceLongField;
-    }
+  public static int getStaticInt(Second s) {
+    return s.getStaticIntField();
+  }
 
-    /// CHECK-START: long Main.setLongThroughParam(Second, long) inliner (before)
-    /// CHECK:                          InvokeVirtual
+  /// CHECK-START: long Main.setLong(Second, long) inliner (before)
+  /// CHECK:                          InvokeVirtual
 
-    /// CHECK-START: long Main.setLongThroughParam(Second, long) inliner (after)
-    /// CHECK:                          InvokeVirtual
+  /// CHECK-START: long Main.setLong(Second, long) inliner (after)
+  /// CHECK:                          InstanceFieldSet
 
-    /// CHECK-START: long Main.setLongThroughParam(Second, long) inliner (after)
-    /// CHECK-NOT:                      InstanceFieldSet
+  /// CHECK-START: long Main.setLong(Second, long) inliner (after)
+  /// CHECK-NOT:                      InvokeVirtual
 
-    public static long setLongThroughParam(Second s, long value) {
-      s.setInstanceLongFieldThroughParam(s, value);
-      return s.instanceLongField;
-    }
+  public static long setLong(Second s, long value) {
+    s.setInstanceLongField(-1, value);
+    return s.instanceLongField;
+  }
 
-    /// CHECK-START: float Main.setStaticFloat(Second, float) inliner (before)
-    /// CHECK:                          InvokeVirtual
+  /// CHECK-START: long Main.setLongReturnArg2(Second, long, int) inliner (before)
+  /// CHECK:                          InvokeVirtual
 
-    /// CHECK-START: float Main.setStaticFloat(Second, float) inliner (after)
-    /// CHECK:                          InvokeVirtual
+  /// CHECK-START: long Main.setLongReturnArg2(Second, long, int) inliner (after)
+  /// CHECK-DAG:  <<Second:l\d+>>     ParameterValue
+  /// CHECK-DAG:  <<Value:j\d+>>      ParameterValue
+  /// CHECK-DAG:  <<Arg2:i\d+>>       ParameterValue
+  /// CHECK-DAG:  <<NullCk:l\d+>>     NullCheck [<<Second>>]
+  /// CHECK-DAG:                      InstanceFieldSet [<<NullCk>>,<<Value>>]
+  /// CHECK-DAG:  <<NullCk2:l\d+>>    NullCheck [<<Second>>]
+  /// CHECK-DAG:  <<IGet:j\d+>>       InstanceFieldGet [<<NullCk2>>]
+  /// CHECK-DAG:  <<Conv:j\d+>>       TypeConversion [<<Arg2>>]
+  /// CHECK-DAG:  <<Add:j\d+>>        Add [<<IGet>>,<<Conv>>]
+  /// CHECK-DAG:                      Return [<<Add>>]
 
-    /// CHECK-START: float Main.setStaticFloat(Second, float) inliner (after)
-    /// CHECK-NOT:                      InstanceFieldSet
-    /// CHECK-NOT:                      StaticFieldSet
+  /// CHECK-START: long Main.setLongReturnArg2(Second, long, int) inliner (after)
+  /// CHECK-NOT:                      InvokeVirtual
 
-    public static float setStaticFloat(Second s, float value) {
-      s.setStaticFloatField(value);
-      return s.staticFloatField;
-    }
+  public static long setLongReturnArg2(Second s, long value, int arg2) {
+    int result = s.setInstanceLongFieldReturnArg2(value, arg2);
+    return s.instanceLongField + result;
+  }
 
-    /// CHECK-START: java.lang.Object Main.newObject() inliner (before)
-    /// CHECK-DAG:  <<Obj:l\d+>>        NewInstance
-    // Note: The ArtMethod* (typed as int or long) is optional after sharpening.
-    /// CHECK-DAG:                      InvokeStaticOrDirect [<<Obj>>{{(,[ij]\d+)?}}] method_name:java.lang.Object.<init>
+  /// CHECK-START: long Main.staticSetLong(Second, long) inliner (before)
+  /// CHECK:                          InvokeStaticOrDirect
 
-    /// CHECK-START: java.lang.Object Main.newObject() inliner (after)
-    /// CHECK-NOT:                      InvokeStaticOrDirect
+  /// CHECK-START: long Main.staticSetLong(Second, long) inliner (after)
+  /// CHECK:                          InvokeStaticOrDirect
 
-    public static Object newObject() {
-      return new Object();
-    }
+  /// CHECK-START: long Main.staticSetLong(Second, long) inliner (after)
+  /// CHECK-NOT:                      InstanceFieldSet
 
-    public static void main(String[] args) throws Exception {
-      Second s = new Second();
-
-      // Replaced NOP pattern.
-      staticNop();
-      nop(s);
-      // Replaced "return arg" pattern.
-      assertEquals("arbitrary string", staticReturnArg2("arbitrary string"));
-      assertEquals(4321L, returnArg1(s, 4321L));
-      // Replaced "return const" pattern.
-      assertEquals(9, staticReturn9());
-      assertEquals(7, return7(s));
-      assertEquals(null, staticReturnNull());
-      assertEquals(null, returnNull(s));
-      // Replaced IGET pattern.
-      assertEquals(42, getInt(s));
-      assertEquals(-42.0, getDouble(s));
-      assertEquals(null, getObject(s));
-      assertEquals("dummy", getString(s));
-      // Not replaced IGET pattern.
-      assertEquals(42, staticGetInt(s));
-      assertEquals(-42.0, getDoubleFromParam(s));
-      // SGET.
-      assertEquals(4242, getStaticInt(s));
-      // Replaced IPUT pattern.
-      assertEquals(111L, setLong(s, 111L));
-      assertEquals(345L, setLongReturnArg2(s, 222L, 123));
-      // Not replaced IPUT pattern.
-      assertEquals(222L, staticSetLong(s, 222L));
-      assertEquals(333L, setLongThroughParam(s, 333L));
-      // SPUT.
-      assertEquals(-11.5f, setStaticFloat(s, -11.5f));
-
-      if (newObject() == null) {
-        throw new AssertionError("new Object() cannot be null.");
-      }
+  public static long staticSetLong(Second s, long value) {
+    Second.staticSetInstanceLongField(s, value);
+    return s.instanceLongField;
+  }
+
+  /// CHECK-START: long Main.setLongThroughParam(Second, long) inliner (before)
+  /// CHECK:                          InvokeVirtual
+
+  /// CHECK-START: long Main.setLongThroughParam(Second, long) inliner (after)
+  /// CHECK:                          InvokeVirtual
+
+  /// CHECK-START: long Main.setLongThroughParam(Second, long) inliner (after)
+  /// CHECK-NOT:                      InstanceFieldSet
+
+  public static long setLongThroughParam(Second s, long value) {
+    s.setInstanceLongFieldThroughParam(s, value);
+    return s.instanceLongField;
+  }
+
+  /// CHECK-START: float Main.setStaticFloat(Second, float) inliner (before)
+  /// CHECK:                          InvokeVirtual
+
+  /// CHECK-START: float Main.setStaticFloat(Second, float) inliner (after)
+  /// CHECK:                          InvokeVirtual
+
+  /// CHECK-START: float Main.setStaticFloat(Second, float) inliner (after)
+  /// CHECK-NOT:                      InstanceFieldSet
+  /// CHECK-NOT:                      StaticFieldSet
+
+  public static float setStaticFloat(Second s, float value) {
+    s.setStaticFloatField(value);
+    return s.staticFloatField;
+  }
+
+  /// CHECK-START: java.lang.Object Main.newObject() inliner (before)
+  /// CHECK-DAG:  <<Obj:l\d+>>        NewInstance
+  // Note: The ArtMethod* (typed as int or long) is optional after sharpening.
+  /// CHECK-DAG:                      InvokeStaticOrDirect [<<Obj>>{{(,[ij]\d+)?}}] method_name:java.lang.Object.<init>
+
+  /// CHECK-START: java.lang.Object Main.newObject() inliner (after)
+  /// CHECK-NOT:                      InvokeStaticOrDirect
+
+  public static Object newObject() {
+    return new Object();
+  }
+
+  /// CHECK-START: double Main.constructBase() inliner (before)
+  /// CHECK-DAG:  <<Obj:l\d+>>        NewInstance
+  // Note: The ArtMethod* (typed as int or long) is optional after sharpening.
+  /// CHECK-DAG:                      InvokeStaticOrDirect [<<Obj>>{{(,[ij]\d+)?}}] method_name:Base.<init>
+
+  /// CHECK-START: double Main.constructBase() inliner (after)
+  /// CHECK-NOT:                      InvokeStaticOrDirect
+  /// CHECK-NOT:                      MemoryBarrier
+  /// CHECK-NOT:                      InstanceFieldSet
+
+  public static double constructBase() {
+    Base b = new Base();
+    return b.intField + b.doubleField;
+  }
+
+  /// CHECK-START: double Main.constructBase(int) inliner (before)
+  /// CHECK-DAG:  <<Value:i\d+>>      ParameterValue
+  /// CHECK-DAG:  <<Obj:l\d+>>        NewInstance
+  // Note: The ArtMethod* (typed as int or long) is optional after sharpening.
+  /// CHECK-DAG:                      InvokeStaticOrDirect [<<Obj>>,<<Value>>{{(,[ij]\d+)?}}] method_name:Base.<init>
+
+  /// CHECK-START: double Main.constructBase(int) inliner (after)
+  /// CHECK-NOT:                      InvokeStaticOrDirect
+  /// CHECK-NOT:                      MemoryBarrier
+
+  /// CHECK-START: double Main.constructBase(int) inliner (after)
+  /// CHECK-DAG:  <<Value:i\d+>>      ParameterValue
+  /// CHECK-DAG:  <<Obj:l\d+>>        NewInstance
+  /// CHECK-DAG:                      InstanceFieldSet [<<Obj>>,<<Value>>]
+
+  /// CHECK-START: double Main.constructBase(int) inliner (after)
+  /// CHECK-DAG:                      InstanceFieldSet
+  /// CHECK-NOT:                      InstanceFieldSet
+
+  public static double constructBase(int intValue) {
+    Base b = new Base(intValue);
+    return b.intField + b.doubleField;
+  }
+
+  /// CHECK-START: double Main.constructBaseWith0() inliner (before)
+  /// CHECK-DAG:  <<Value:i\d+>>      IntConstant 0
+  /// CHECK-DAG:  <<Obj:l\d+>>        NewInstance
+  // Note: The ArtMethod* (typed as int or long) is optional after sharpening.
+  /// CHECK-DAG:                      InvokeStaticOrDirect [<<Obj>>,<<Value>>{{(,[ij]\d+)?}}] method_name:Base.<init>
+
+  /// CHECK-START: double Main.constructBaseWith0() inliner (after)
+  /// CHECK-NOT:                      InvokeStaticOrDirect
+  /// CHECK-NOT:                      MemoryBarrier
+  /// CHECK-NOT:                      InstanceFieldSet
+
+  public static double constructBaseWith0() {
+    Base b = new Base(0);
+    return b.intField + b.doubleField;
+  }
+
+  /// CHECK-START: java.lang.String Main.constructBase(java.lang.String) inliner (before)
+  /// CHECK-DAG:  <<Value:l\d+>>      ParameterValue
+  /// CHECK-DAG:  <<Obj:l\d+>>        NewInstance
+  // Note: The ArtMethod* (typed as int or long) is optional after sharpening.
+  /// CHECK-DAG:                      InvokeStaticOrDirect [<<Obj>>,<<Value>>{{(,[ij]\d+)?}}] method_name:Base.<init>
+
+  /// CHECK-START: java.lang.String Main.constructBase(java.lang.String) inliner (after)
+  /// CHECK-NOT:                      InvokeStaticOrDirect
+  /// CHECK-NOT:                      MemoryBarrier
+
+  /// CHECK-START: java.lang.String Main.constructBase(java.lang.String) inliner (after)
+  /// CHECK-DAG:  <<Value:l\d+>>      ParameterValue
+  /// CHECK-DAG:  <<Obj:l\d+>>        NewInstance
+  /// CHECK-DAG:                      InstanceFieldSet [<<Obj>>,<<Value>>]
+
+  /// CHECK-START: java.lang.String Main.constructBase(java.lang.String) inliner (after)
+  /// CHECK-DAG:                      InstanceFieldSet
+  /// CHECK-NOT:                      InstanceFieldSet
+
+  public static String constructBase(String stringValue) {
+    Base b = new Base(stringValue);
+    return b.stringField;
+  }
+
+  /// CHECK-START: java.lang.String Main.constructBaseWithNullString() inliner (before)
+  /// CHECK-DAG:  <<Null:l\d+>>       NullConstant
+  /// CHECK-DAG:  <<Obj:l\d+>>        NewInstance
+  // Note: The ArtMethod* (typed as int or long) is optional after sharpening.
+  /// CHECK-DAG:                      InvokeStaticOrDirect [<<Obj>>,<<Null>>{{(,[ij]\d+)?}}] method_name:Base.<init>
+
+  /// CHECK-START: java.lang.String Main.constructBaseWithNullString() inliner (after)
+  /// CHECK-NOT:                      InvokeStaticOrDirect
+  /// CHECK-NOT:                      MemoryBarrier
+
+  /// CHECK-START: java.lang.String Main.constructBaseWithNullString() inliner (after)
+  /// CHECK-NOT:                      InstanceFieldSet
+
+  public static String constructBaseWithNullString() {
+    String stringValue = null;
+    Base b = new Base(stringValue);
+    return b.stringField;
+  }
+
+  /// CHECK-START: double Main.constructBase(double, java.lang.Object) inliner (before)
+  /// CHECK-DAG:  <<DValue:d\d+>>     ParameterValue
+  /// CHECK-DAG:  <<OValue:l\d+>>     ParameterValue
+  /// CHECK-DAG:  <<Obj:l\d+>>        NewInstance
+  // Note: The ArtMethod* (typed as int or long) is optional after sharpening.
+  /// CHECK-DAG:                      InvokeStaticOrDirect [<<Obj>>,<<DValue>>,<<OValue>>{{(,[ij]\d+)?}}] method_name:Base.<init>
+
+  /// CHECK-START: double Main.constructBase(double, java.lang.Object) inliner (after)
+  /// CHECK-NOT:                      InvokeStaticOrDirect
+  /// CHECK-NOT:                      MemoryBarrier
+
+  /// CHECK-START: double Main.constructBase(double, java.lang.Object) inliner (after)
+  /// CHECK-DAG:  <<DValue:d\d+>>     ParameterValue
+  /// CHECK-DAG:  <<OValue:l\d+>>     ParameterValue
+  /// CHECK-DAG:  <<Obj:l\d+>>        NewInstance
+  /// CHECK-DAG:                      InstanceFieldSet [<<Obj>>,<<DValue>>]
+  /// CHECK-DAG:                      InstanceFieldSet [<<Obj>>,<<OValue>>]
+
+  /// CHECK-START: double Main.constructBase(double, java.lang.Object) inliner (after)
+  /// CHECK-DAG:                      InstanceFieldSet
+  /// CHECK-DAG:                      InstanceFieldSet
+  /// CHECK-NOT:                      InstanceFieldSet
+
+  public static double constructBase(double doubleValue, Object objectValue) {
+    Base b = new Base(doubleValue, objectValue);
+    return (b.objectField != null) ? b.doubleField : -b.doubleField;
+  }
+
+  /// CHECK-START: double Main.constructBase(int, double, java.lang.Object) inliner (before)
+  /// CHECK-DAG:  <<IValue:i\d+>>     ParameterValue
+  /// CHECK-DAG:  <<DValue:d\d+>>     ParameterValue
+  /// CHECK-DAG:  <<OValue:l\d+>>     ParameterValue
+  /// CHECK-DAG:  <<Obj:l\d+>>        NewInstance
+  // Note: The ArtMethod* (typed as int or long) is optional after sharpening.
+  /// CHECK-DAG:                      InvokeStaticOrDirect [<<Obj>>,<<IValue>>,<<DValue>>,<<OValue>>{{(,[ij]\d+)?}}] method_name:Base.<init>
+
+  /// CHECK-START: double Main.constructBase(int, double, java.lang.Object) inliner (after)
+  /// CHECK-NOT:                      InvokeStaticOrDirect
+  /// CHECK-NOT:                      MemoryBarrier
+
+  /// CHECK-START: double Main.constructBase(int, double, java.lang.Object) inliner (after)
+  /// CHECK-DAG:  <<IValue:i\d+>>     ParameterValue
+  /// CHECK-DAG:  <<DValue:d\d+>>     ParameterValue
+  /// CHECK-DAG:  <<OValue:l\d+>>     ParameterValue
+  /// CHECK-DAG:  <<Obj:l\d+>>        NewInstance
+  /// CHECK-DAG:                      InstanceFieldSet [<<Obj>>,<<IValue>>]
+  /// CHECK-DAG:                      InstanceFieldSet [<<Obj>>,<<DValue>>]
+  /// CHECK-DAG:                      InstanceFieldSet [<<Obj>>,<<OValue>>]
+
+  /// CHECK-START: double Main.constructBase(int, double, java.lang.Object) inliner (after)
+  /// CHECK-DAG:                      InstanceFieldSet
+  /// CHECK-DAG:                      InstanceFieldSet
+  /// CHECK-DAG:                      InstanceFieldSet
+  /// CHECK-NOT:                      InstanceFieldSet
+
+  public static double constructBase(int intValue, double doubleValue, Object objectValue) {
+    Base b = new Base(intValue, doubleValue, objectValue);
+    double tmp = b.intField + b.doubleField;
+    return (b.objectField != null) ? tmp : -tmp;
+  }
+
+  /// CHECK-START: double Main.constructBaseWith0DoubleNull(double) inliner (before)
+  /// CHECK-DAG:  <<IValue:i\d+>>     IntConstant 0
+  /// CHECK-DAG:  <<DValue:d\d+>>     ParameterValue
+  /// CHECK-DAG:  <<OValue:l\d+>>     NullConstant
+  /// CHECK-DAG:  <<Obj:l\d+>>        NewInstance
+  // Note: The ArtMethod* (typed as int or long) is optional after sharpening.
+  /// CHECK-DAG:                      InvokeStaticOrDirect [<<Obj>>,<<IValue>>,<<DValue>>,<<OValue>>{{(,[ij]\d+)?}}] method_name:Base.<init>
+
+  /// CHECK-START: double Main.constructBaseWith0DoubleNull(double) inliner (after)
+  /// CHECK-NOT:                      InvokeStaticOrDirect
+  /// CHECK-NOT:                      MemoryBarrier
+
+  /// CHECK-START: double Main.constructBaseWith0DoubleNull(double) inliner (after)
+  /// CHECK-DAG:  <<DValue:d\d+>>     ParameterValue
+  /// CHECK-DAG:  <<Obj:l\d+>>        NewInstance
+  /// CHECK-DAG:                      InstanceFieldSet [<<Obj>>,<<DValue>>]
+
+  /// CHECK-START: double Main.constructBaseWith0DoubleNull(double) inliner (after)
+  /// CHECK-DAG:                      InstanceFieldSet
+  /// CHECK-NOT:                      InstanceFieldSet
+
+  public static double constructBaseWith0DoubleNull(double doubleValue) {
+    Base b = new Base(0, doubleValue, null);
+    double tmp = b.intField + b.doubleField;
+    return (b.objectField != null) ? tmp : -tmp;
+  }
+
+  /// CHECK-START: double Main.constructBase(int, double, java.lang.Object, java.lang.String) inliner (before)
+  /// CHECK-DAG:  <<IValue:i\d+>>     ParameterValue
+  /// CHECK-DAG:  <<DValue:d\d+>>     ParameterValue
+  /// CHECK-DAG:  <<Obj:l\d+>>        NewInstance
+  // Note: The ArtMethod* (typed as int or long) is optional after sharpening.
+  /// CHECK-DAG:                      InvokeStaticOrDirect [<<Obj>>,<<IValue>>,<<DValue>>,{{l\d+}},{{l\d+}}{{(,[ij]\d+)?}}] method_name:Base.<init>
+
+  /// CHECK-START: double Main.constructBase(int, double, java.lang.Object, java.lang.String) inliner (after)
+  /// CHECK-DAG:  <<IValue:i\d+>>     ParameterValue
+  /// CHECK-DAG:  <<DValue:d\d+>>     ParameterValue
+  /// CHECK-DAG:  <<Obj:l\d+>>        NewInstance
+  // Note: The ArtMethod* (typed as int or long) is optional after sharpening.
+  /// CHECK-DAG:                      InvokeStaticOrDirect [<<Obj>>,<<IValue>>,<<DValue>>,{{l\d+}},{{l\d+}}{{(,[ij]\d+)?}}] method_name:Base.<init>
+
+  /// CHECK-START: double Main.constructBase(int, double, java.lang.Object, java.lang.String) inliner (after)
+  /// CHECK-NOT:                      InstanceFieldSet
+
+  public static double constructBase(
+      int intValue, double doubleValue, Object objectValue, String stringValue) {
+    Base b = new Base(intValue, doubleValue, objectValue, stringValue);
+    double tmp = b.intField + b.doubleField;
+    tmp = (b.objectField != null) ? tmp : -tmp;
+    return (b.stringField != null) ? 2.0 * tmp : 0.5 * tmp;
+  }
+
+  /// CHECK-START: double Main.constructBase(double) inliner (before)
+  /// CHECK-DAG:  <<Value:d\d+>>      ParameterValue
+  /// CHECK-DAG:  <<Obj:l\d+>>        NewInstance
+  // Note: The ArtMethod* (typed as int or long) is optional after sharpening.
+  /// CHECK-DAG:                      InvokeStaticOrDirect [<<Obj>>,<<Value>>{{(,[ij]\d+)?}}] method_name:Base.<init>
+
+  /// CHECK-START: double Main.constructBase(double) inliner (after)
+  /// CHECK-NOT:                      InvokeStaticOrDirect
+  /// CHECK-NOT:                      MemoryBarrier
+
+  /// CHECK-START: double Main.constructBase(double) inliner (after)
+  /// CHECK-DAG:  <<Value:d\d+>>      ParameterValue
+  /// CHECK-DAG:  <<Obj:l\d+>>        NewInstance
+  /// CHECK-DAG:                      InstanceFieldSet [<<Obj>>,<<Value>>]
+
+  /// CHECK-START: double Main.constructBase(double) inliner (after)
+  /// CHECK-DAG:                      InstanceFieldSet
+  /// CHECK-NOT:                      InstanceFieldSet
+
+  public static double constructBase(double doubleValue) {
+    Base b = new Base(doubleValue);
+    return b.intField + b.doubleField;
+  }
+
+  /// CHECK-START: double Main.constructBaseWith0d() inliner (before)
+  /// CHECK-DAG:  <<Value:d\d+>>      DoubleConstant
+  /// CHECK-DAG:  <<Obj:l\d+>>        NewInstance
+  // Note: The ArtMethod* (typed as int or long) is optional after sharpening.
+  /// CHECK-DAG:                      InvokeStaticOrDirect [<<Obj>>,<<Value>>{{(,[ij]\d+)?}}] method_name:Base.<init>
+
+  /// CHECK-START: double Main.constructBaseWith0d() inliner (after)
+  /// CHECK-NOT:                      InvokeStaticOrDirect
+  /// CHECK-NOT:                      MemoryBarrier
+  /// CHECK-NOT:                      InstanceFieldSet
+
+  public static double constructBaseWith0d() {
+    Base b = new Base(0.0);
+    return b.intField + b.doubleField;
+  }
+
+  /// CHECK-START: double Main.constructBase(java.lang.Object) inliner (before)
+  /// CHECK-DAG:  <<OValue:l\d+>>     ParameterValue
+  /// CHECK-DAG:  <<Obj:l\d+>>        NewInstance
+  // Note: The ArtMethod* (typed as int or long) is optional after sharpening.
+  /// CHECK-DAG:                      InvokeStaticOrDirect [<<Obj>>,<<OValue>>{{(,[ij]\d+)?}}] method_name:Base.<init>
+
+  /// CHECK-START: double Main.constructBase(java.lang.Object) inliner (after)
+  /// CHECK-DAG:  <<OValue:l\d+>>     ParameterValue
+  /// CHECK-DAG:  <<Obj:l\d+>>        NewInstance
+  // Note: The ArtMethod* (typed as int or long) is optional after sharpening.
+  /// CHECK-DAG:                      InvokeStaticOrDirect [<<Obj>>,<<OValue>>{{(,[ij]\d+)?}}] method_name:Base.<init>
+
+  /// CHECK-START: double Main.constructBase(java.lang.Object) inliner (after)
+  /// CHECK-NOT:                      InstanceFieldSet
+
+  public static double constructBase(Object objectValue) {
+    Base b = new Base(objectValue);
+    double tmp = b.intField + b.doubleField;
+    return (b.objectField != null) ? tmp + 1.0 : tmp - 1.0;
+  }
+
+  /// CHECK-START: double Main.constructBase(int, long) inliner (before)
+  /// CHECK-DAG:  <<IValue:i\d+>>     ParameterValue
+  /// CHECK-DAG:  <<JValue:j\d+>>     ParameterValue
+  /// CHECK-DAG:  <<Obj:l\d+>>        NewInstance
+  // Note: The ArtMethod* (typed as int or long) is optional after sharpening.
+  /// CHECK-DAG:                      InvokeStaticOrDirect [<<Obj>>,<<IValue>>,<<JValue>>{{(,[ij]\d+)?}}] method_name:Base.<init>
+
+  /// CHECK-START: double Main.constructBase(int, long) inliner (after)
+  /// CHECK-NOT:                      InvokeStaticOrDirect
+  /// CHECK-NOT:                      MemoryBarrier
+
+  /// CHECK-START: double Main.constructBase(int, long) inliner (after)
+  /// CHECK-DAG:  <<IValue:i\d+>>     ParameterValue
+  /// CHECK-DAG:  <<Obj:l\d+>>        NewInstance
+  /// CHECK-DAG:                      InstanceFieldSet [<<Obj>>,<<IValue>>]
+
+  /// CHECK-START: double Main.constructBase(int, long) inliner (after)
+  /// CHECK-DAG:                      InstanceFieldSet
+  /// CHECK-NOT:                      InstanceFieldSet
+
+  public static double constructBase(int intValue, long dummy) {
+    Base b = new Base(intValue, dummy);
+    return b.intField + b.doubleField;
+  }
+
+  /// CHECK-START: double Main.constructDerived() inliner (before)
+  /// CHECK-DAG:  <<Obj:l\d+>>        NewInstance
+  // Note: The ArtMethod* (typed as int or long) is optional after sharpening.
+  /// CHECK-DAG:                      InvokeStaticOrDirect [<<Obj>>{{(,[ij]\d+)?}}] method_name:Derived.<init>
+
+  /// CHECK-START: double Main.constructDerived() inliner (after)
+  /// CHECK-NOT:                      InvokeStaticOrDirect
+  /// CHECK-NOT:                      MemoryBarrier
+  /// CHECK-NOT:                      InstanceFieldSet
+
+  public static double constructDerived() {
+    Derived d = new Derived();
+    return d.intField + d.doubleField;
+  }
+
+  /// CHECK-START: double Main.constructDerived(int) inliner (before)
+  /// CHECK-DAG:  <<Value:i\d+>>      ParameterValue
+  /// CHECK-DAG:  <<Obj:l\d+>>        NewInstance
+  // Note: The ArtMethod* (typed as int or long) is optional after sharpening.
+  /// CHECK-DAG:                      InvokeStaticOrDirect [<<Obj>>,<<Value>>{{(,[ij]\d+)?}}] method_name:Derived.<init>
+
+  /// CHECK-START: double Main.constructDerived(int) inliner (after)
+  /// CHECK-NOT:                      InvokeStaticOrDirect
+  /// CHECK-NOT:                      MemoryBarrier
+
+  /// CHECK-START: double Main.constructDerived(int) inliner (after)
+  /// CHECK-DAG:  <<Value:i\d+>>      ParameterValue
+  /// CHECK-DAG:  <<Obj:l\d+>>        NewInstance
+  /// CHECK-DAG:                      InstanceFieldSet [<<Obj>>,<<Value>>]
+
+  /// CHECK-START: double Main.constructDerived(int) inliner (after)
+  /// CHECK-DAG:                      InstanceFieldSet
+  /// CHECK-NOT:                      InstanceFieldSet
+
+  public static double constructDerived(int intValue) {
+    Derived d = new Derived(intValue);
+    return d.intField + d.doubleField;
+  }
+
+  /// CHECK-START: double Main.constructDerivedWith0() inliner (before)
+  /// CHECK-DAG:  <<Value:i\d+>>      IntConstant 0
+  /// CHECK-DAG:  <<Obj:l\d+>>        NewInstance
+  // Note: The ArtMethod* (typed as int or long) is optional after sharpening.
+  /// CHECK-DAG:                      InvokeStaticOrDirect [<<Obj>>,<<Value>>{{(,[ij]\d+)?}}] method_name:Derived.<init>
+
+  /// CHECK-START: double Main.constructDerivedWith0() inliner (after)
+  /// CHECK-NOT:                      InvokeStaticOrDirect
+  /// CHECK-NOT:                      MemoryBarrier
+  /// CHECK-NOT:                      InstanceFieldSet
+
+  public static double constructDerivedWith0() {
+    Derived d = new Derived(0);
+    return d.intField + d.doubleField;
+  }
+
+  /// CHECK-START: java.lang.String Main.constructDerived(java.lang.String) inliner (before)
+  /// CHECK-DAG:  <<Value:l\d+>>      ParameterValue
+  /// CHECK-DAG:  <<Obj:l\d+>>        NewInstance
+  // Note: The ArtMethod* (typed as int or long) is optional after sharpening.
+  /// CHECK-DAG:                      InvokeStaticOrDirect [<<Obj>>,<<Value>>{{(,[ij]\d+)?}}] method_name:Derived.<init>
+
+  /// CHECK-START: java.lang.String Main.constructDerived(java.lang.String) inliner (after)
+  /// CHECK-NOT:                      InvokeStaticOrDirect
+  /// CHECK-NOT:                      MemoryBarrier
+
+  /// CHECK-START: java.lang.String Main.constructDerived(java.lang.String) inliner (after)
+  /// CHECK-NOT:                      InstanceFieldSet
+
+  public static String constructDerived(String stringValue) {
+    Derived d = new Derived(stringValue);
+    return d.stringField;
+  }
+
+  /// CHECK-START: double Main.constructDerived(double) inliner (before)
+  /// CHECK-DAG:  <<Value:d\d+>>      ParameterValue
+  /// CHECK-DAG:  <<Obj:l\d+>>        NewInstance
+  // Note: The ArtMethod* (typed as int or long) is optional after sharpening.
+  /// CHECK-DAG:                      InvokeStaticOrDirect [<<Obj>>,<<Value>>{{(,[ij]\d+)?}}] method_name:Derived.<init>
+
+  /// CHECK-START: double Main.constructDerived(double) inliner (after)
+  /// CHECK-NOT:                      InvokeStaticOrDirect
+  /// CHECK-NOT:                      MemoryBarrier
+
+  /// CHECK-START: double Main.constructDerived(double) inliner (after)
+  /// CHECK-DAG:  <<Value:d\d+>>      ParameterValue
+  /// CHECK-DAG:  <<Obj:l\d+>>        NewInstance
+  /// CHECK-DAG:                      InstanceFieldSet [<<Obj>>,<<Value>>]
+
+  /// CHECK-START: double Main.constructDerived(double) inliner (after)
+  /// CHECK-DAG:                      InstanceFieldSet
+  /// CHECK-NOT:                      InstanceFieldSet
+
+  public static double constructDerived(double doubleValue) {
+    Derived d = new Derived(doubleValue);
+    return d.intField + d.doubleField;
+  }
+
+  /// CHECK-START: double Main.constructDerivedWith0d() inliner (before)
+  /// CHECK-DAG:  <<Value:d\d+>>      DoubleConstant
+  /// CHECK-DAG:  <<Obj:l\d+>>        NewInstance
+  // Note: The ArtMethod* (typed as int or long) is optional after sharpening.
+  /// CHECK-DAG:                      InvokeStaticOrDirect [<<Obj>>,<<Value>>{{(,[ij]\d+)?}}] method_name:Derived.<init>
+
+  /// CHECK-START: double Main.constructDerivedWith0d() inliner (after)
+  /// CHECK-NOT:                      InvokeStaticOrDirect
+  /// CHECK-NOT:                      MemoryBarrier
+  /// CHECK-NOT:                      InstanceFieldSet
+
+  public static double constructDerivedWith0d() {
+    Derived d = new Derived(0.0);
+    return d.intField + d.doubleField;
+  }
+
+  /// CHECK-START: double Main.constructDerived(int, double, java.lang.Object) inliner (before)
+  /// CHECK-DAG:  <<IValue:i\d+>>     ParameterValue
+  /// CHECK-DAG:  <<DValue:d\d+>>     ParameterValue
+  /// CHECK-DAG:  <<OValue:l\d+>>     ParameterValue
+  /// CHECK-DAG:  <<Obj:l\d+>>        NewInstance
+  // Note: The ArtMethod* (typed as int or long) is optional after sharpening.
+  /// CHECK-DAG:                      InvokeStaticOrDirect [<<Obj>>,<<IValue>>,<<DValue>>,<<OValue>>{{(,[ij]\d+)?}}] method_name:Derived.<init>
+
+  /// CHECK-START: double Main.constructDerived(int, double, java.lang.Object) inliner (after)
+  /// CHECK-NOT:                      InvokeStaticOrDirect
+  /// CHECK-NOT:                      MemoryBarrier
+
+  /// CHECK-START: double Main.constructDerived(int, double, java.lang.Object) inliner (after)
+  /// CHECK-DAG:  <<DValue:d\d+>>     ParameterValue
+  /// CHECK-DAG:  <<Obj:l\d+>>        NewInstance
+  /// CHECK-DAG:                      InstanceFieldSet [<<Obj>>,<<DValue>>]
+
+  /// CHECK-START: double Main.constructDerived(int, double, java.lang.Object) inliner (after)
+  /// CHECK-DAG:                      InstanceFieldSet
+  /// CHECK-NOT:                      InstanceFieldSet
+
+  public static double constructDerived(int intValue, double doubleValue, Object objectValue) {
+    Derived d = new Derived(intValue, doubleValue, objectValue);
+    double tmp = d.intField + d.doubleField;
+    return (d.objectField != null) ? tmp : -tmp;
+  }
+
+  /// CHECK-START: double Main.constructDerived(int, double, java.lang.Object, java.lang.String) inliner (before)
+  /// CHECK-DAG:  <<IValue:i\d+>>     ParameterValue
+  /// CHECK-DAG:  <<DValue:d\d+>>     ParameterValue
+  /// CHECK-DAG:  <<Obj:l\d+>>        NewInstance
+  // Note: The ArtMethod* (typed as int or long) is optional after sharpening.
+  /// CHECK-DAG:                      InvokeStaticOrDirect [<<Obj>>,<<IValue>>,<<DValue>>,{{l\d+}},{{l\d+}}{{(,[ij]\d+)?}}] method_name:Derived.<init>
+
+  /// CHECK-START: double Main.constructDerived(int, double, java.lang.Object, java.lang.String) inliner (after)
+  /// CHECK-DAG:  <<IValue:i\d+>>     ParameterValue
+  /// CHECK-DAG:  <<DValue:d\d+>>     ParameterValue
+  /// CHECK-DAG:  <<Obj:l\d+>>        NewInstance
+  // Note: The ArtMethod* (typed as int or long) is optional after sharpening.
+  /// CHECK-DAG:                      InvokeStaticOrDirect [<<Obj>>,<<IValue>>,<<DValue>>,{{l\d+}},{{l\d+}}{{(,[ij]\d+)?}}] method_name:Derived.<init>
+
+  /// CHECK-START: double Main.constructDerived(int, double, java.lang.Object, java.lang.String) inliner (after)
+  /// CHECK-NOT:                      InstanceFieldSet
+
+  public static double constructDerived(
+      int intValue, double doubleValue, Object objectValue, String stringValue) {
+    Derived d = new Derived(intValue, doubleValue, objectValue, stringValue);
+    double tmp = d.intField + d.doubleField;
+    tmp = (d.objectField != null) ? tmp : -tmp;
+    return (d.stringField != null) ? 2.0 * tmp : 0.5 * tmp;
+  }
+
+  /// CHECK-START: double Main.constructDerived(float) inliner (before)
+  /// CHECK-DAG:  <<Value:f\d+>>      ParameterValue
+  /// CHECK-DAG:  <<Obj:l\d+>>        NewInstance
+  // Note: The ArtMethod* (typed as int or long) is optional after sharpening.
+  /// CHECK-DAG:                      InvokeStaticOrDirect [<<Obj>>,<<Value>>{{(,[ij]\d+)?}}] method_name:Derived.<init>
+
+  /// CHECK-START: double Main.constructDerived(float) inliner (after)
+  /// CHECK-NOT:                      InvokeStaticOrDirect
+  /// CHECK-NOT:                      MemoryBarrier
+
+  /// CHECK-START: double Main.constructDerived(float) inliner (after)
+  /// CHECK-DAG:  <<Value:f\d+>>      ParameterValue
+  /// CHECK-DAG:  <<Obj:l\d+>>        NewInstance
+  /// CHECK-DAG:                      InstanceFieldSet [<<Obj>>,<<Value>>]
+
+  /// CHECK-START: double Main.constructDerived(float) inliner (after)
+  /// CHECK-DAG:                      InstanceFieldSet
+  /// CHECK-NOT:                      InstanceFieldSet
+
+  public static double constructDerived(float floatValue) {
+    Derived d = new Derived(floatValue);
+    return d.intField + d.doubleField + d.floatField;
+  }
+
+  /// CHECK-START: double Main.constructDerived(int, double, java.lang.Object, float) inliner (before)
+  /// CHECK-DAG:  <<IValue:i\d+>>     ParameterValue
+  /// CHECK-DAG:  <<DValue:d\d+>>     ParameterValue
+  /// CHECK-DAG:  <<OValue:l\d+>>     ParameterValue
+  /// CHECK-DAG:  <<FValue:f\d+>>     ParameterValue
+  /// CHECK-DAG:  <<Obj:l\d+>>        NewInstance
+  // Note: The ArtMethod* (typed as int or long) is optional after sharpening.
+  /// CHECK-DAG:                      InvokeStaticOrDirect [<<Obj>>,<<IValue>>,<<DValue>>,<<OValue>>,<<FValue>>{{(,[ij]\d+)?}}] method_name:Derived.<init>
+
+  /// CHECK-START: double Main.constructDerived(int, double, java.lang.Object, float) inliner (after)
+  /// CHECK-NOT:                      InvokeStaticOrDirect
+  /// CHECK-NOT:                      MemoryBarrier
+
+  /// CHECK-START: double Main.constructDerived(int, double, java.lang.Object, float) inliner (after)
+  /// CHECK-DAG:  <<IValue:i\d+>>     ParameterValue
+  /// CHECK-DAG:  <<DValue:d\d+>>     ParameterValue
+  /// CHECK-DAG:  <<FValue:f\d+>>     ParameterValue
+  /// CHECK-DAG:  <<Obj:l\d+>>        NewInstance
+  /// CHECK-DAG:                      InstanceFieldSet [<<Obj>>,<<IValue>>]
+  /// CHECK-DAG:                      InstanceFieldSet [<<Obj>>,<<DValue>>]
+  /// CHECK-DAG:                      InstanceFieldSet [<<Obj>>,<<FValue>>]
+
+  /// CHECK-START: double Main.constructDerived(int, double, java.lang.Object, float) inliner (after)
+  /// CHECK-DAG:                      InstanceFieldSet
+  /// CHECK-DAG:                      InstanceFieldSet
+  /// CHECK-DAG:                      InstanceFieldSet
+  /// CHECK-NOT:                      InstanceFieldSet
+
+  public static double constructDerived(
+      int intValue, double doubleValue, Object objectValue, float floatValue) {
+    Derived d = new Derived(intValue, doubleValue, objectValue, floatValue);
+    double tmp = d.intField + d.doubleField + d.floatField;
+    return (d.objectField != null) ? tmp : -tmp;
+  }
+
+  /// CHECK-START: int Main.constructBaseWithFinalField() inliner (before)
+  /// CHECK-DAG:  <<Obj:l\d+>>        NewInstance
+  // Note: The ArtMethod* (typed as int or long) is optional after sharpening.
+  /// CHECK-DAG:                      InvokeStaticOrDirect [<<Obj>>{{(,[ij]\d+)?}}] method_name:BaseWithFinalField.<init>
+
+  /// CHECK-START: int Main.constructBaseWithFinalField() inliner (after)
+  /// CHECK-NOT:                      InvokeStaticOrDirect
+  /// CHECK-NOT:                      MemoryBarrier
+  /// CHECK-NOT:                      InstanceFieldSet
+
+  public static int constructBaseWithFinalField() {
+    BaseWithFinalField b = new BaseWithFinalField();
+    return b.intField;
+  }
+
+  /// CHECK-START: int Main.constructBaseWithFinalField(int) inliner (before)
+  /// CHECK-DAG:  <<Value:i\d+>>      ParameterValue
+  /// CHECK-DAG:  <<Obj:l\d+>>        NewInstance
+  // Note: The ArtMethod* (typed as int or long) is optional after sharpening.
+  /// CHECK-DAG:                      InvokeStaticOrDirect [<<Obj>>,<<Value>>{{(,[ij]\d+)?}}] method_name:BaseWithFinalField.<init>
+
+  /// CHECK-START: int Main.constructBaseWithFinalField(int) inliner (after)
+  /// CHECK-NOT:                      InvokeStaticOrDirect
+
+  /// CHECK-START: int Main.constructBaseWithFinalField(int) inliner (after)
+  /// CHECK-DAG:  <<Value:i\d+>>      ParameterValue
+  /// CHECK-DAG:  <<Obj:l\d+>>        NewInstance
+  /// CHECK-DAG:                      InstanceFieldSet [<<Obj>>,<<Value>>]
+  /// CHECK-DAG:                      MemoryBarrier
+
+  /// CHECK-START: int Main.constructBaseWithFinalField(int) inliner (after)
+  /// CHECK-DAG:                      InstanceFieldSet
+  /// CHECK-NOT:                      InstanceFieldSet
+
+  public static int constructBaseWithFinalField(int intValue) {
+    BaseWithFinalField b = new BaseWithFinalField(intValue);
+    return b.intField;
+  }
+
+  /// CHECK-START: int Main.constructBaseWithFinalFieldWith0() inliner (before)
+  /// CHECK-DAG:  <<Value:i\d+>>      IntConstant 0
+  /// CHECK-DAG:  <<Obj:l\d+>>        NewInstance
+  // Note: The ArtMethod* (typed as int or long) is optional after sharpening.
+  /// CHECK-DAG:                      InvokeStaticOrDirect [<<Obj>>,<<Value>>{{(,[ij]\d+)?}}] method_name:BaseWithFinalField.<init>
+
+  /// CHECK-START: int Main.constructBaseWithFinalFieldWith0() inliner (after)
+  /// CHECK-NOT:                      InvokeStaticOrDirect
+  /// CHECK-NOT:                      MemoryBarrier
+  /// CHECK-NOT:                      InstanceFieldSet
+
+  public static int constructBaseWithFinalFieldWith0() {
+    BaseWithFinalField b = new BaseWithFinalField(0);
+    return b.intField;
+  }
+
+  /// CHECK-START: double Main.constructDerivedWithFinalField() inliner (before)
+  /// CHECK-DAG:  <<Obj:l\d+>>        NewInstance
+  // Note: The ArtMethod* (typed as int or long) is optional after sharpening.
+  /// CHECK-DAG:                      InvokeStaticOrDirect [<<Obj>>{{(,[ij]\d+)?}}] method_name:DerivedWithFinalField.<init>
+
+  /// CHECK-START: double Main.constructDerivedWithFinalField() inliner (after)
+  /// CHECK-NOT:                      InvokeStaticOrDirect
+  /// CHECK-NOT:                      MemoryBarrier
+  /// CHECK-NOT:                      InstanceFieldSet
+
+  public static double constructDerivedWithFinalField() {
+    DerivedWithFinalField d = new DerivedWithFinalField();
+    return d.intField + d.doubleField;
+  }
+
+  /// CHECK-START: double Main.constructDerivedWithFinalField(int) inliner (before)
+  /// CHECK-DAG:  <<Value:i\d+>>      ParameterValue
+  /// CHECK-DAG:  <<Obj:l\d+>>        NewInstance
+  // Note: The ArtMethod* (typed as int or long) is optional after sharpening.
+  /// CHECK-DAG:                      InvokeStaticOrDirect [<<Obj>>,<<Value>>{{(,[ij]\d+)?}}] method_name:DerivedWithFinalField.<init>
+
+  /// CHECK-START: double Main.constructDerivedWithFinalField(int) inliner (after)
+  /// CHECK-NOT:                      InvokeStaticOrDirect
+
+  /// CHECK-START: double Main.constructDerivedWithFinalField(int) inliner (after)
+  /// CHECK-DAG:  <<Value:i\d+>>      ParameterValue
+  /// CHECK-DAG:  <<Obj:l\d+>>        NewInstance
+  /// CHECK-DAG:                      InstanceFieldSet [<<Obj>>,<<Value>>]
+  /// CHECK-DAG:                      MemoryBarrier
+
+  /// CHECK-START: double Main.constructDerivedWithFinalField(int) inliner (after)
+  /// CHECK-DAG:                      InstanceFieldSet
+  /// CHECK-NOT:                      InstanceFieldSet
+
+  public static double constructDerivedWithFinalField(int intValue) {
+    DerivedWithFinalField d = new DerivedWithFinalField(intValue);
+    return d.intField + d.doubleField;
+  }
+
+  /// CHECK-START: double Main.constructDerivedWithFinalFieldWith0() inliner (before)
+  /// CHECK-DAG:  <<Value:i\d+>>      IntConstant 0
+  /// CHECK-DAG:  <<Obj:l\d+>>        NewInstance
+  // Note: The ArtMethod* (typed as int or long) is optional after sharpening.
+  /// CHECK-DAG:                      InvokeStaticOrDirect [<<Obj>>,<<Value>>{{(,[ij]\d+)?}}] method_name:DerivedWithFinalField.<init>
+
+  /// CHECK-START: double Main.constructDerivedWithFinalFieldWith0() inliner (after)
+  /// CHECK-NOT:                      InvokeStaticOrDirect
+  /// CHECK-NOT:                      MemoryBarrier
+  /// CHECK-NOT:                      InstanceFieldSet
+
+  public static double constructDerivedWithFinalFieldWith0() {
+    DerivedWithFinalField d = new DerivedWithFinalField(0);
+    return d.intField + d.doubleField;
+  }
+
+  /// CHECK-START: double Main.constructDerivedWithFinalField(double) inliner (before)
+  /// CHECK-DAG:  <<Value:d\d+>>      ParameterValue
+  /// CHECK-DAG:  <<Obj:l\d+>>        NewInstance
+  // Note: The ArtMethod* (typed as int or long) is optional after sharpening.
+  /// CHECK-DAG:                      InvokeStaticOrDirect [<<Obj>>,<<Value>>{{(,[ij]\d+)?}}] method_name:DerivedWithFinalField.<init>
+
+  /// CHECK-START: double Main.constructDerivedWithFinalField(double) inliner (after)
+  /// CHECK-NOT:                      InvokeStaticOrDirect
+
+  /// CHECK-START: double Main.constructDerivedWithFinalField(double) inliner (after)
+  /// CHECK-DAG:  <<Value:d\d+>>      ParameterValue
+  /// CHECK-DAG:  <<Obj:l\d+>>        NewInstance
+  /// CHECK-DAG:                      InstanceFieldSet [<<Obj>>,<<Value>>]
+  /// CHECK-DAG:                      MemoryBarrier
+
+  /// CHECK-START: double Main.constructDerivedWithFinalField(double) inliner (after)
+  /// CHECK-DAG:                      InstanceFieldSet
+  /// CHECK-NOT:                      InstanceFieldSet
+
+  public static double constructDerivedWithFinalField(double doubleValue) {
+    DerivedWithFinalField d = new DerivedWithFinalField(doubleValue);
+    return d.intField + d.doubleField;
+  }
+
+  /// CHECK-START: double Main.constructDerivedWithFinalFieldWith0d() inliner (before)
+  /// CHECK-DAG:  <<Value:d\d+>>      DoubleConstant
+  /// CHECK-DAG:  <<Obj:l\d+>>        NewInstance
+  // Note: The ArtMethod* (typed as int or long) is optional after sharpening.
+  /// CHECK-DAG:                      InvokeStaticOrDirect [<<Obj>>,<<Value>>{{(,[ij]\d+)?}}] method_name:DerivedWithFinalField.<init>
+
+  /// CHECK-START: double Main.constructDerivedWithFinalFieldWith0d() inliner (after)
+  /// CHECK-NOT:                      InvokeStaticOrDirect
+  /// CHECK-NOT:                      MemoryBarrier
+  /// CHECK-NOT:                      InstanceFieldSet
+
+  public static double constructDerivedWithFinalFieldWith0d() {
+    DerivedWithFinalField d = new DerivedWithFinalField(0.0);
+    return d.intField + d.doubleField;
+  }
+
+  /// CHECK-START: double Main.constructDerivedWithFinalField(int, double) inliner (before)
+  /// CHECK-DAG:  <<IValue:i\d+>>     ParameterValue
+  /// CHECK-DAG:  <<DValue:d\d+>>     ParameterValue
+  /// CHECK-DAG:  <<Obj:l\d+>>        NewInstance
+  // Note: The ArtMethod* (typed as int or long) is optional after sharpening.
+  /// CHECK-DAG:                      InvokeStaticOrDirect [<<Obj>>,<<IValue>>,<<DValue>>{{(,[ij]\d+)?}}] method_name:DerivedWithFinalField.<init>
+
+  /// CHECK-START: double Main.constructDerivedWithFinalField(int, double) inliner (after)
+  /// CHECK-NOT:                      InvokeStaticOrDirect
+
+  /// CHECK-START: double Main.constructDerivedWithFinalField(int, double) inliner (after)
+  /// CHECK-DAG:  <<Value:d\d+>>      ParameterValue
+  /// CHECK-DAG:  <<Obj:l\d+>>        NewInstance
+  /// CHECK-DAG:                      InstanceFieldSet [<<Obj>>,<<Value>>]
+  /// CHECK-DAG:                      MemoryBarrier
+
+  /// CHECK-START: double Main.constructDerivedWithFinalField(int, double) inliner (after)
+  /// CHECK-DAG:                      InstanceFieldSet
+  /// CHECK-DAG:                      InstanceFieldSet
+  /// CHECK-NOT:                      InstanceFieldSet
+
+  /// CHECK-START: double Main.constructDerivedWithFinalField(int, double) inliner (after)
+  /// CHECK-DAG:                      MemoryBarrier
+  /// CHECK-NOT:                      MemoryBarrier
+
+  public static double constructDerivedWithFinalField(int intValue, double doubleValue) {
+    DerivedWithFinalField d = new DerivedWithFinalField(intValue, doubleValue);
+    return d.intField + d.doubleField;
+  }
+
+  /// CHECK-START: double Main.constructDerivedWithFinalFieldWith0And0d() inliner (before)
+  /// CHECK-DAG:  <<IValue:i\d+>>     IntConstant 0
+  /// CHECK-DAG:  <<DValue:d\d+>>     DoubleConstant
+  /// CHECK-DAG:  <<Obj:l\d+>>        NewInstance
+  // Note: The ArtMethod* (typed as int or long) is optional after sharpening.
+  /// CHECK-DAG:                      InvokeStaticOrDirect [<<Obj>>,<<IValue>>,<<DValue>>{{(,[ij]\d+)?}}] method_name:DerivedWithFinalField.<init>
+
+  /// CHECK-START: double Main.constructDerivedWithFinalFieldWith0And0d() inliner (after)
+  /// CHECK-NOT:                      InvokeStaticOrDirect
+  /// CHECK-NOT:                      MemoryBarrier
+  /// CHECK-NOT:                      InstanceFieldSet
+
+  public static double constructDerivedWithFinalFieldWith0And0d() {
+    DerivedWithFinalField d = new DerivedWithFinalField(0, 0.0);
+    return d.intField + d.doubleField;
+  }
+
+  /// CHECK-START: int Main.constructDerivedInSecondDex() inliner (before)
+  /// CHECK-DAG:  <<Obj:l\d+>>        NewInstance
+  // Note: The ArtMethod* (typed as int or long) is optional after sharpening.
+  /// CHECK-DAG:                      InvokeStaticOrDirect [<<Obj>>{{(,[ij]\d+)?}}] method_name:DerivedInSecondDex.<init>
+
+  /// CHECK-START: int Main.constructDerivedInSecondDex() inliner (after)
+  /// CHECK-NOT:                      InvokeStaticOrDirect
+  /// CHECK-NOT:                      MemoryBarrier
+  /// CHECK-NOT:                      InstanceFieldSet
+
+  public static int constructDerivedInSecondDex() {
+    DerivedInSecondDex d = new DerivedInSecondDex();
+    return d.intField;
+  }
+
+  /// CHECK-START: int Main.constructDerivedInSecondDex(int) inliner (before)
+  /// CHECK-DAG:  <<Value:i\d+>>      ParameterValue
+  /// CHECK-DAG:  <<Obj:l\d+>>        NewInstance
+  // Note: The ArtMethod* (typed as int or long) is optional after sharpening.
+  /// CHECK-DAG:                      InvokeStaticOrDirect [<<Obj>>,<<Value>>{{(,[ij]\d+)?}}] method_name:DerivedInSecondDex.<init>
+
+  /// CHECK-START: int Main.constructDerivedInSecondDex(int) inliner (after)
+  /// CHECK-DAG:  <<Value:i\d+>>      ParameterValue
+  /// CHECK-DAG:  <<Obj:l\d+>>        NewInstance
+  // Note: The ArtMethod* (typed as int or long) is optional after sharpening.
+  /// CHECK-DAG:                      InvokeStaticOrDirect [<<Obj>>,<<Value>>{{(,[ij]\d+)?}}] method_name:DerivedInSecondDex.<init>
+
+  /// CHECK-START: int Main.constructDerivedInSecondDex(int) inliner (after)
+  /// CHECK-NOT:                      MemoryBarrier
+  /// CHECK-NOT:                      InstanceFieldSet
+
+  public static int constructDerivedInSecondDex(int intValue) {
+    DerivedInSecondDex d = new DerivedInSecondDex(intValue);
+    return d.intField;
+  }
+
+  /// CHECK-START: int Main.constructDerivedInSecondDexWith0() inliner (before)
+  /// CHECK-DAG:  <<Value:i\d+>>      IntConstant 0
+  /// CHECK-DAG:  <<Obj:l\d+>>        NewInstance
+  // Note: The ArtMethod* (typed as int or long) is optional after sharpening.
+  /// CHECK-DAG:                      InvokeStaticOrDirect [<<Obj>>,<<Value>>{{(,[ij]\d+)?}}] method_name:DerivedInSecondDex.<init>
+
+  /// CHECK-START: int Main.constructDerivedInSecondDexWith0() inliner (after)
+  /// CHECK-DAG:  <<Value:i\d+>>      IntConstant 0
+  /// CHECK-DAG:  <<Obj:l\d+>>        NewInstance
+  // Note: The ArtMethod* (typed as int or long) is optional after sharpening.
+  /// CHECK-DAG:                      InvokeStaticOrDirect [<<Obj>>,<<Value>>{{(,[ij]\d+)?}}] method_name:DerivedInSecondDex.<init>
+
+  /// CHECK-START: int Main.constructDerivedInSecondDexWith0() inliner (after)
+  /// CHECK-NOT:                      MemoryBarrier
+  /// CHECK-NOT:                      InstanceFieldSet
+
+  public static int constructDerivedInSecondDexWith0() {
+    DerivedInSecondDex d = new DerivedInSecondDex(0);
+    return d.intField;
+  }
+
+  /// CHECK-START: int Main.constructDerivedInSecondDex(long) inliner (before)
+  /// CHECK-DAG:  <<Value:j\d+>>      ParameterValue
+  /// CHECK-DAG:  <<Obj:l\d+>>        NewInstance
+  // Note: The ArtMethod* (typed as int or long) is optional after sharpening.
+  /// CHECK-DAG:                      InvokeStaticOrDirect [<<Obj>>,<<Value>>{{(,[ij]\d+)?}}] method_name:DerivedInSecondDex.<init>
+
+  /// CHECK-START: int Main.constructDerivedInSecondDex(long) inliner (after)
+  /// CHECK-NOT:                      InvokeStaticOrDirect
+  /// CHECK-NOT:                      MemoryBarrier
+  /// CHECK-NOT:                      InstanceFieldSet
+
+  public static int constructDerivedInSecondDex(long dummy) {
+    DerivedInSecondDex d = new DerivedInSecondDex(dummy);
+    return d.intField;
+  }
+
+  public static void main(String[] args) throws Exception {
+    Second s = new Second();
+
+    // Replaced NOP pattern.
+    staticNop();
+    nop(s);
+    // Replaced "return arg" pattern.
+    assertEquals("arbitrary string", staticReturnArg2("arbitrary string"));
+    assertEquals(4321L, returnArg1(s, 4321L));
+    // Replaced "return const" pattern.
+    assertEquals(9, staticReturn9());
+    assertEquals(7, return7(s));
+    assertEquals(null, staticReturnNull());
+    assertEquals(null, returnNull(s));
+    // Replaced IGET pattern.
+    assertEquals(42, getInt(s));
+    assertEquals(-42.0, getDouble(s));
+    assertEquals(null, getObject(s));
+    assertEquals("dummy", getString(s));
+    // Not replaced IGET pattern.
+    assertEquals(42, staticGetInt(s));
+    assertEquals(-42.0, getDoubleFromParam(s));
+    // SGET.
+    assertEquals(4242, getStaticInt(s));
+    // Replaced IPUT pattern.
+    assertEquals(111L, setLong(s, 111L));
+    assertEquals(345L, setLongReturnArg2(s, 222L, 123));
+    // Not replaced IPUT pattern.
+    assertEquals(222L, staticSetLong(s, 222L));
+    assertEquals(333L, setLongThroughParam(s, 333L));
+    // SPUT.
+    assertEquals(-11.5f, setStaticFloat(s, -11.5f));
+
+    if (newObject() == null) {
+      throw new AssertionError("new Object() cannot be null.");
     }
 
-    private static void assertEquals(int expected, int actual) {
-      if (expected != actual) {
-        throw new AssertionError("Wrong result: " + expected + " != " + actual);
-      }
+    assertEquals(0.0, constructBase());
+    assertEquals(42.0, constructBase(42));
+    assertEquals(0.0, constructBaseWith0());
+    assertEquals("something", constructBase("something"));
+    assertEquals(null, constructBaseWithNullString());
+    assertEquals(11.0, constructBase(11.0, new Object()));
+    assertEquals(-12.0, constructBase(12.0, null));
+    assertEquals(30.0, constructBase(17, 13.0, new Object()));
+    assertEquals(-34.0, constructBase(19, 15.0, null));
+    assertEquals(-22.5, constructBaseWith0DoubleNull(22.5));
+    assertEquals(-8.0, constructBase(2, 14.0, null, null));
+    assertEquals(-64.0, constructBase(4, 28.0, null, "dummy"));
+    assertEquals(13.0, constructBase(24, 2.0, new Object(), null));
+    assertEquals(30.0, constructBase(11, 4.0, new Object(), "dummy"));
+    assertEquals(43.0, constructBase(43.0));
+    assertEquals(0.0, constructBaseWith0d());
+    assertEquals(1.0, constructBase(new Object()));
+    assertEquals(-1.0, constructBase((Object) null));
+    assertEquals(123.0, constructBase(123, 65L));
+
+    assertEquals(0.0, constructDerived());
+    assertEquals(73.0, constructDerived(73));
+    assertEquals(0.0, constructDerivedWith0());
+    assertEquals(null, constructDerived("something else"));
+    assertEquals(18.0, constructDerived(18.0));
+    assertEquals(0.0, constructDerivedWith0d());
+    assertEquals(-7.0, constructDerived(5, 7.0, new Object()));
+    assertEquals(-4.0, constructDerived(9, 4.0, null));
+    assertEquals(0.0, constructDerived(1, 9.0, null, null));
+    assertEquals(0.0, constructDerived(2, 8.0, null, "dummy"));
+    assertEquals(0.0, constructDerived(3, 7.0, new Object(), null));
+    assertEquals(0.0, constructDerived(4, 6.0, new Object(), "dummy"));
+    assertEquals(17.0, constructDerived(17.0f));
+    assertEquals(-5.5, constructDerived(6, -7.0, new Object(), 6.5f));
+
+    assertEquals(0, constructBaseWithFinalField());
+    assertEquals(77, constructBaseWithFinalField(77));
+    assertEquals(0, constructBaseWithFinalFieldWith0());
+    assertEquals(0.0, constructDerivedWithFinalField());
+    assertEquals(-33.0, constructDerivedWithFinalField(-33));
+    assertEquals(0.0, constructDerivedWithFinalFieldWith0());
+    assertEquals(-44.0, constructDerivedWithFinalField(-44.0));
+    assertEquals(0.0, constructDerivedWithFinalFieldWith0d());
+    assertEquals(88, constructDerivedWithFinalField(22, 66.0));
+    assertEquals(0.0, constructDerivedWithFinalFieldWith0And0d());
+
+    assertEquals(0, constructDerivedInSecondDex());
+    assertEquals(123, constructDerivedInSecondDex(123));
+    assertEquals(0, constructDerivedInSecondDexWith0());
+    assertEquals(0, constructDerivedInSecondDex(7L));
+  }
+
+  private static void assertEquals(int expected, int actual) {
+    if (expected != actual) {
+      throw new AssertionError("Wrong result: " + expected + " != " + actual);
     }
+  }
 
-    private static void assertEquals(double expected, double actual) {
-      if (expected != actual) {
-        throw new AssertionError("Wrong result: " + expected + " != " + actual);
-      }
+  private static void assertEquals(double expected, double actual) {
+    if (expected != actual) {
+      throw new AssertionError("Wrong result: " + expected + " != " + actual);
     }
+  }
 
-    private static void assertEquals(Object expected, Object actual) {
-      if (expected != actual && (expected == null || !expected.equals(actual))) {
-        throw new AssertionError("Wrong result: " + expected + " != " + actual);
-      }
+  private static void assertEquals(Object expected, Object actual) {
+    if (expected != actual && (expected == null || !expected.equals(actual))) {
+      throw new AssertionError("Wrong result: " + expected + " != " + actual);
     }
+  }
 }
index a8938fa..239570e 100644 (file)
@@ -235,6 +235,18 @@ ifdef dist_goal
         $(IMAGE_TYPES), $(PICTEST_TYPES), $(DEBUGGABLE_TYPES), $(TEST_ART_TIMING_SENSITIVE_RUN_TESTS), $(ALL_ADDRESS_SIZES))
 endif
 
+# 569-checker-pattern-replacement tests behaviour present only on host.
+TEST_ART_BROKEN_TARGET_TESTS := \
+  569-checker-pattern-replacement
+
+ifneq (,$(filter target,$(TARGET_TYPES)))
+  ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,target,$(RUN_TYPES),$(PREBUILD_TYPES), \
+      $(COMPILER_TYPES),$(RELOCATE_TYPES),$(TRACE_TYPES),$(GC_TYPES),$(JNI_TYPES), \
+      $(IMAGE_TYPES), $(PICTEST_TYPES), $(DEBUGGABLE_TYPES), $(TEST_ART_BROKEN_TARGET_TESTS), $(ALL_ADDRESS_SIZES))
+endif
+
+TEST_ART_BROKEN_TARGET_TESTS :=
+
 # Tests that require python3.
 TEST_ART_PYTHON3_DEPENDENCY_RUN_TESTS := \
   960-default-smali \