Merge "Tidy up logging."
diff --git a/compiler/dex/quick/x86/int_x86.cc b/compiler/dex/quick/x86/int_x86.cc
index 07034cb..acf5599 100755
--- a/compiler/dex/quick/x86/int_x86.cc
+++ b/compiler/dex/quick/x86/int_x86.cc
@@ -858,6 +858,11 @@
     RegLocation rl_dest = InlineTargetWide(info);
     int res_vreg, src1_vreg, src2_vreg;
 
+    if (rl_dest.s_reg_low == INVALID_SREG) {
+      // Result is unused, the code is dead. Inlining successful, no code generated.
+      return true;
+    }
+
     /*
      * If the result register is the same as the second element, then we
      * need to be careful. The reason is that the first copy will
diff --git a/compiler/optimizing/builder.cc b/compiler/optimizing/builder.cc
index 2f1a092..4d575cb 100644
--- a/compiler/optimizing/builder.cc
+++ b/compiler/optimizing/builder.cc
@@ -171,6 +171,7 @@
 
   const uint16_t* code_ptr = code_item.insns_;
   const uint16_t* code_end = code_item.insns_ + code_item.insns_size_in_code_units_;
+  code_start_ = code_ptr;
 
   // Setup the graph with the entry block and exit block.
   graph_ = new (arena_) HGraph(arena_);
@@ -416,6 +417,7 @@
 
   DCHECK_EQ(argument_index, number_of_arguments);
   current_block_->AddInstruction(invoke);
+  latest_result_ = invoke;
   return true;
 }
 
@@ -503,6 +505,62 @@
   }
 }
 
+void HGraphBuilder::BuildFilledNewArray(uint32_t dex_offset,
+                                        uint32_t type_index,
+                                        uint32_t number_of_vreg_arguments,
+                                        bool is_range,
+                                        uint32_t* args,
+                                        uint32_t register_index) {
+  HInstruction* length = GetIntConstant(number_of_vreg_arguments);
+  HInstruction* object = new (arena_) HNewArray(length, dex_offset, type_index);
+  current_block_->AddInstruction(object);
+
+  const char* descriptor = dex_file_->StringByTypeIdx(type_index);
+  DCHECK_EQ(descriptor[0], '[') << descriptor;
+  char primitive = descriptor[1];
+  DCHECK(primitive == 'I'
+      || primitive == 'L'
+      || primitive == '[') << descriptor;
+  bool is_reference_array = (primitive == 'L') || (primitive == '[');
+  Primitive::Type type = is_reference_array ? Primitive::kPrimNot : Primitive::kPrimInt;
+
+  Temporaries temps(graph_, 1);
+  temps.Add(object);
+  for (size_t i = 0; i < number_of_vreg_arguments; ++i) {
+    HInstruction* value = LoadLocal(is_range ? register_index + i : args[i], type);
+    HInstruction* index = GetIntConstant(i);
+    current_block_->AddInstruction(
+        new (arena_) HArraySet(object, index, value, type, dex_offset));
+  }
+  latest_result_ = object;
+}
+
+template <typename T>
+void HGraphBuilder::BuildFillArrayData(HInstruction* object,
+                                       const T* data,
+                                       uint32_t element_count,
+                                       Primitive::Type anticipated_type,
+                                       uint32_t dex_offset) {
+  for (uint32_t i = 0; i < element_count; ++i) {
+    HInstruction* index = GetIntConstant(i);
+    HInstruction* value = GetIntConstant(data[i]);
+    current_block_->AddInstruction(new (arena_) HArraySet(
+      object, index, value, anticipated_type, dex_offset));
+  }
+}
+
+void HGraphBuilder::BuildFillWideArrayData(HInstruction* object,
+                                           const uint64_t* data,
+                                           uint32_t element_count,
+                                           uint32_t dex_offset) {
+  for (uint32_t i = 0; i < element_count; ++i) {
+    HInstruction* index = GetIntConstant(i);
+    HInstruction* value = GetLongConstant(data[i]);
+    current_block_->AddInstruction(new (arena_) HArraySet(
+      object, index, value, Primitive::kPrimLong, dex_offset));
+  }
+}
+
 void HGraphBuilder::PotentiallyAddSuspendCheck(int32_t target_offset, uint32_t dex_offset) {
   if (target_offset <= 0) {
     // Unconditionnally add a suspend check to backward branches. We can remove
@@ -735,6 +793,16 @@
       break;
     }
 
+    case Instruction::MUL_FLOAT: {
+      Binop_23x<HMul>(instruction, Primitive::kPrimFloat);
+      break;
+    }
+
+    case Instruction::MUL_DOUBLE: {
+      Binop_23x<HMul>(instruction, Primitive::kPrimDouble);
+      break;
+    }
+
     case Instruction::ADD_LONG_2ADDR: {
       Binop_12x<HAdd>(instruction, Primitive::kPrimLong);
       break;
@@ -770,6 +838,16 @@
       break;
     }
 
+    case Instruction::MUL_FLOAT_2ADDR: {
+      Binop_12x<HMul>(instruction, Primitive::kPrimFloat);
+      break;
+    }
+
+    case Instruction::MUL_DOUBLE_2ADDR: {
+      Binop_12x<HMul>(instruction, Primitive::kPrimDouble);
+      break;
+    }
+
     case Instruction::ADD_INT_LIT16: {
       Binop_22s<HAdd>(instruction, false);
       break;
@@ -807,10 +885,88 @@
       break;
     }
 
+    case Instruction::NEW_ARRAY: {
+      HInstruction* length = LoadLocal(instruction.VRegB_22c(), Primitive::kPrimInt);
+      current_block_->AddInstruction(
+          new (arena_) HNewArray(length, dex_offset, instruction.VRegC_22c()));
+      UpdateLocal(instruction.VRegA_22c(), current_block_->GetLastInstruction());
+      break;
+    }
+
+    case Instruction::FILLED_NEW_ARRAY: {
+      uint32_t number_of_vreg_arguments = instruction.VRegA_35c();
+      uint32_t type_index = instruction.VRegB_35c();
+      uint32_t args[5];
+      instruction.GetVarArgs(args);
+      BuildFilledNewArray(dex_offset, type_index, number_of_vreg_arguments, false, args, 0);
+      break;
+    }
+
+    case Instruction::FILLED_NEW_ARRAY_RANGE: {
+      uint32_t number_of_vreg_arguments = instruction.VRegA_3rc();
+      uint32_t type_index = instruction.VRegB_3rc();
+      uint32_t register_index = instruction.VRegC_3rc();
+      BuildFilledNewArray(
+          dex_offset, type_index, number_of_vreg_arguments, true, nullptr, register_index);
+      break;
+    }
+
+    case Instruction::FILL_ARRAY_DATA: {
+      Temporaries temps(graph_, 1);
+      HInstruction* array = LoadLocal(instruction.VRegA_31t(), Primitive::kPrimNot);
+      HNullCheck* null_check = new (arena_) HNullCheck(array, dex_offset);
+      current_block_->AddInstruction(null_check);
+      temps.Add(null_check);
+
+      HInstruction* length = new (arena_) HArrayLength(null_check);
+      current_block_->AddInstruction(length);
+
+      int32_t payload_offset = instruction.VRegB_31t() + dex_offset;
+      const Instruction::ArrayDataPayload* payload =
+          reinterpret_cast<const Instruction::ArrayDataPayload*>(code_start_ + payload_offset);
+      const uint8_t* data = payload->data;
+      uint32_t element_count = payload->element_count;
+
+      // Implementation of this DEX instruction seems to be that the bounds check is
+      // done before doing any stores.
+      HInstruction* last_index = GetIntConstant(payload->element_count - 1);
+      current_block_->AddInstruction(new (arena_) HBoundsCheck(last_index, length, dex_offset));
+
+      switch (payload->element_width) {
+        case 1:
+          BuildFillArrayData(null_check, data, element_count, Primitive::kPrimByte, dex_offset);
+          break;
+        case 2:
+          BuildFillArrayData(null_check,
+                             reinterpret_cast<const uint16_t*>(data),
+                             element_count,
+                             Primitive::kPrimShort,
+                             dex_offset);
+          break;
+        case 4:
+          BuildFillArrayData(null_check,
+                             reinterpret_cast<const uint32_t*>(data),
+                             element_count,
+                             Primitive::kPrimInt,
+                             dex_offset);
+          break;
+        case 8:
+          BuildFillWideArrayData(null_check,
+                                 reinterpret_cast<const uint64_t*>(data),
+                                 element_count,
+                                 dex_offset);
+          break;
+        default:
+          LOG(FATAL) << "Unknown element width for " << payload->element_width;
+      }
+      break;
+    }
+
     case Instruction::MOVE_RESULT:
     case Instruction::MOVE_RESULT_WIDE:
     case Instruction::MOVE_RESULT_OBJECT:
-      UpdateLocal(instruction.VRegA(), current_block_->GetLastInstruction());
+      UpdateLocal(instruction.VRegA(), latest_result_);
+      latest_result_ = nullptr;
       break;
 
     case Instruction::CMP_LONG: {
diff --git a/compiler/optimizing/builder.h b/compiler/optimizing/builder.h
index 90e50ad..c5e02db 100644
--- a/compiler/optimizing/builder.h
+++ b/compiler/optimizing/builder.h
@@ -48,7 +48,9 @@
         dex_file_(dex_file),
         dex_compilation_unit_(dex_compilation_unit),
         compiler_driver_(driver),
-        return_type_(Primitive::GetType(dex_compilation_unit_->GetShorty()[0])) {}
+        return_type_(Primitive::GetType(dex_compilation_unit_->GetShorty()[0])),
+        code_start_(nullptr),
+        latest_result_(nullptr) {}
 
   // Only for unit testing.
   HGraphBuilder(ArenaAllocator* arena, Primitive::Type return_type = Primitive::kPrimInt)
@@ -64,7 +66,9 @@
         dex_file_(nullptr),
         dex_compilation_unit_(nullptr),
         compiler_driver_(nullptr),
-        return_type_(return_type) {}
+        return_type_(return_type),
+        code_start_(nullptr),
+        latest_result_(nullptr) {}
 
   HGraph* BuildGraph(const DexFile::CodeItem& code);
 
@@ -129,6 +133,31 @@
                    uint32_t* args,
                    uint32_t register_index);
 
+  // Builds a new array node and the instructions that fill it.
+  void BuildFilledNewArray(uint32_t dex_offset,
+                           uint32_t type_index,
+                           uint32_t number_of_vreg_arguments,
+                           bool is_range,
+                           uint32_t* args,
+                           uint32_t register_index);
+
+  // Fills the given object with data as specified in the fill-array-data
+  // instruction. Currently only used for non-reference and non-floating point
+  // arrays.
+  template <typename T>
+  void BuildFillArrayData(HInstruction* object,
+                          const T* data,
+                          uint32_t element_count,
+                          Primitive::Type anticipated_type,
+                          uint32_t dex_offset);
+
+  // Fills the given object with data as specified in the fill-array-data
+  // instruction. The data must be for long and double arrays.
+  void BuildFillWideArrayData(HInstruction* object,
+                              const uint64_t* data,
+                              uint32_t element_count,
+                              uint32_t dex_offset);
+
   ArenaAllocator* const arena_;
 
   // A list of the size of the dex code holding block information for
@@ -151,6 +180,14 @@
   CompilerDriver* const compiler_driver_;
   const Primitive::Type return_type_;
 
+  // The pointer in the dex file where the instructions of the code item
+  // being currently compiled start.
+  const uint16_t* code_start_;
+
+  // The last invoke or fill-new-array being built. Only to be
+  // used by move-result instructions.
+  HInstruction* latest_result_;
+
   DISALLOW_COPY_AND_ASSIGN(HGraphBuilder);
 };
 
diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc
index 24b7c2d..7ed802e 100644
--- a/compiler/optimizing/code_generator_arm.cc
+++ b/compiler/optimizing/code_generator_arm.cc
@@ -1065,7 +1065,7 @@
   switch (neg->GetResultType()) {
     case Primitive::kPrimInt:
       DCHECK(in.IsRegister());
-      __ rsbs(out.As<Register>(), in.As<Register>(), ShifterOperand(0));
+      __ rsb(out.As<Register>(), in.As<Register>(), ShifterOperand(0));
       break;
 
     case Primitive::kPrimLong:
@@ -1219,15 +1219,16 @@
       break;
     }
 
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
-      LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
+    case Primitive::kPrimFloat:
+    case Primitive::kPrimDouble: {
+      locations->SetInAt(0, Location::RequiresFpuRegister());
+      locations->SetInAt(1, Location::RequiresFpuRegister());
+      locations->SetOut(Location::RequiresFpuRegister());
       break;
+    }
 
     default:
-      LOG(FATAL) << "Unimplemented mul type " << mul->GetResultType();
+      LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
   }
 }
 
@@ -1271,15 +1272,21 @@
       __ add(out_hi, out_hi, ShifterOperand(IP));
       break;
     }
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
-      LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
+
+    case Primitive::kPrimFloat: {
+      __ vmuls(FromDToLowS(out.As<DRegister>()),
+               FromDToLowS(first.As<DRegister>()),
+               FromDToLowS(second.As<DRegister>()));
       break;
+    }
+
+    case Primitive::kPrimDouble: {
+      __ vmuld(out.As<DRegister>(), first.As<DRegister>(), second.As<DRegister>());
+      break;
+    }
 
     default:
-      LOG(FATAL) << "Unimplemented mul type " << mul->GetResultType();
+      LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
   }
 }
 
@@ -1305,6 +1312,29 @@
   DCHECK(!codegen_->IsLeafMethod());
 }
 
+void LocationsBuilderARM::VisitNewArray(HNewArray* instruction) {
+  LocationSummary* locations =
+      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
+  InvokeRuntimeCallingConvention calling_convention;
+  locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
+  locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
+  locations->SetOut(Location::RegisterLocation(R0));
+  locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
+}
+
+void InstructionCodeGeneratorARM::VisitNewArray(HNewArray* instruction) {
+  InvokeRuntimeCallingConvention calling_convention;
+  LoadCurrentMethod(calling_convention.GetRegisterAt(1));
+  __ LoadImmediate(calling_convention.GetRegisterAt(0), instruction->GetTypeIndex());
+
+  int32_t offset = QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pAllocArrayWithAccessCheck).Int32Value();
+  __ LoadFromOffset(kLoadWord, LR, TR, offset);
+  __ blx(LR);
+
+  codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
+  DCHECK(!codegen_->IsLeafMethod());
+}
+
 void LocationsBuilderARM::VisitParameterValue(HParameterValue* instruction) {
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc
index 2550518..5f01265 100644
--- a/compiler/optimizing/code_generator_x86.cc
+++ b/compiler/optimizing/code_generator_x86.cc
@@ -491,17 +491,23 @@
     Immediate imm(instruction->AsIntConstant()->GetValue());
     if (location.IsRegister()) {
       __ movl(location.As<Register>(), imm);
-    } else {
+    } else if (location.IsStackSlot()) {
       __ movl(Address(ESP, location.GetStackIndex()), imm);
+    } else {
+      DCHECK(location.IsConstant());
+      DCHECK_EQ(location.GetConstant(), instruction);
     }
   } else if (instruction->IsLongConstant()) {
     int64_t value = instruction->AsLongConstant()->GetValue();
     if (location.IsRegister()) {
       __ movl(location.AsRegisterPairLow<Register>(), Immediate(Low32Bits(value)));
       __ movl(location.AsRegisterPairHigh<Register>(), Immediate(High32Bits(value)));
-    } else {
+    } else if (location.IsDoubleStackSlot()) {
       __ movl(Address(ESP, location.GetStackIndex()), Immediate(Low32Bits(value)));
       __ movl(Address(ESP, location.GetHighStackIndex(kX86WordSize)), Immediate(High32Bits(value)));
+    } else {
+      DCHECK(location.IsConstant());
+      DCHECK_EQ(location.GetConstant(), instruction);
     }
   } else if (instruction->IsLoadLocal()) {
     int slot = GetStackSlot(instruction->AsLoadLocal()->GetLocal());
@@ -1206,16 +1212,16 @@
       locations->AddTemp(Location::RegisterLocation(EDX));
       break;
     }
-
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
-      LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
+    case Primitive::kPrimFloat:
+    case Primitive::kPrimDouble: {
+      locations->SetInAt(0, Location::RequiresFpuRegister());
+      locations->SetInAt(1, Location::RequiresFpuRegister());
+      locations->SetOut(Location::SameAsFirstInput());
       break;
+    }
 
     default:
-      LOG(FATAL) << "Unimplemented mul type " << mul->GetResultType();
+      LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
   }
 }
 
@@ -1277,15 +1283,18 @@
       break;
     }
 
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
-      LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
+    case Primitive::kPrimFloat: {
+      __ mulss(first.As<XmmRegister>(), second.As<XmmRegister>());
       break;
+    }
+
+    case Primitive::kPrimDouble: {
+      __ mulsd(first.As<XmmRegister>(), second.As<XmmRegister>());
+      break;
+    }
 
     default:
-      LOG(FATAL) << "Unimplemented mul type " << mul->GetResultType();
+      LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
   }
 }
 
@@ -1310,6 +1319,28 @@
   DCHECK(!codegen_->IsLeafMethod());
 }
 
+void LocationsBuilderX86::VisitNewArray(HNewArray* instruction) {
+  LocationSummary* locations =
+      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
+  locations->SetOut(Location::RegisterLocation(EAX));
+  InvokeRuntimeCallingConvention calling_convention;
+  locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
+  locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
+  locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
+}
+
+void InstructionCodeGeneratorX86::VisitNewArray(HNewArray* instruction) {
+  InvokeRuntimeCallingConvention calling_convention;
+  LoadCurrentMethod(calling_convention.GetRegisterAt(1));
+  __ movl(calling_convention.GetRegisterAt(0), Immediate(instruction->GetTypeIndex()));
+
+  __ fs()->call(
+      Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pAllocArrayWithAccessCheck)));
+
+  codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
+  DCHECK(!codegen_->IsLeafMethod());
+}
+
 void LocationsBuilderX86::VisitParameterValue(HParameterValue* instruction) {
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc
index 6174ac6..38a40dc 100644
--- a/compiler/optimizing/code_generator_x86_64.cc
+++ b/compiler/optimizing/code_generator_x86_64.cc
@@ -407,16 +407,22 @@
     Immediate imm(instruction->AsIntConstant()->GetValue());
     if (location.IsRegister()) {
       __ movl(location.As<CpuRegister>(), imm);
-    } else {
+    } else if (location.IsStackSlot()) {
       __ movl(Address(CpuRegister(RSP), location.GetStackIndex()), imm);
+    } else {
+      DCHECK(location.IsConstant());
+      DCHECK_EQ(location.GetConstant(), instruction);
     }
   } else if (instruction->IsLongConstant()) {
     int64_t value = instruction->AsLongConstant()->GetValue();
     if (location.IsRegister()) {
       __ movq(location.As<CpuRegister>(), Immediate(value));
-    } else {
+    } else if (location.IsDoubleStackSlot()) {
       __ movq(CpuRegister(TMP), Immediate(value));
       __ movq(Address(CpuRegister(RSP), location.GetStackIndex()), CpuRegister(TMP));
+    } else {
+      DCHECK(location.IsConstant());
+      DCHECK_EQ(location.GetConstant(), instruction);
     }
   } else if (instruction->IsLoadLocal()) {
     switch (instruction->GetType()) {
@@ -1160,16 +1166,16 @@
       locations->SetOut(Location::SameAsFirstInput());
       break;
     }
-
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
-      LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
+    case Primitive::kPrimFloat:
+    case Primitive::kPrimDouble: {
+      locations->SetInAt(0, Location::RequiresFpuRegister());
+      locations->SetInAt(1, Location::RequiresFpuRegister());
+      locations->SetOut(Location::SameAsFirstInput());
       break;
+    }
 
     default:
-      LOG(FATAL) << "Unimplemented mul type " << mul->GetResultType();
+      LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
   }
 }
 
@@ -1196,15 +1202,18 @@
       break;
     }
 
-    case Primitive::kPrimBoolean:
-    case Primitive::kPrimByte:
-    case Primitive::kPrimChar:
-    case Primitive::kPrimShort:
-      LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
+    case Primitive::kPrimFloat: {
+      __ mulss(first.As<XmmRegister>(), second.As<XmmRegister>());
       break;
+    }
+
+    case Primitive::kPrimDouble: {
+      __ mulsd(first.As<XmmRegister>(), second.As<XmmRegister>());
+      break;
+    }
 
     default:
-      LOG(FATAL) << "Unimplemented mul type " << mul->GetResultType();
+      LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
   }
 }
 
@@ -1229,6 +1238,28 @@
   codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
 }
 
+void LocationsBuilderX86_64::VisitNewArray(HNewArray* instruction) {
+  LocationSummary* locations =
+      new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
+  InvokeRuntimeCallingConvention calling_convention;
+  locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
+  locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
+  locations->SetOut(Location::RegisterLocation(RAX));
+  locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
+}
+
+void InstructionCodeGeneratorX86_64::VisitNewArray(HNewArray* instruction) {
+  InvokeRuntimeCallingConvention calling_convention;
+  LoadCurrentMethod(CpuRegister(calling_convention.GetRegisterAt(1)));
+  __ movq(CpuRegister(calling_convention.GetRegisterAt(0)), Immediate(instruction->GetTypeIndex()));
+
+  __ gs()->call(Address::Absolute(
+      QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pAllocArrayWithAccessCheck), true));
+
+  DCHECK(!codegen_->IsLeafMethod());
+  codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
+}
+
 void LocationsBuilderX86_64::VisitParameterValue(HParameterValue* instruction) {
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
diff --git a/compiler/optimizing/codegen_test.cc b/compiler/optimizing/codegen_test.cc
index 8bb12de..af4cf73 100644
--- a/compiler/optimizing/codegen_test.cc
+++ b/compiler/optimizing/codegen_test.cc
@@ -135,8 +135,8 @@
   const DexFile::CodeItem* item = reinterpret_cast<const DexFile::CodeItem*>(data);
   HGraph* graph = builder.BuildGraph(*item);
   // Remove suspend checks, they cannot be executed in this context.
-  RemoveSuspendChecks(graph);
   ASSERT_NE(graph, nullptr);
+  RemoveSuspendChecks(graph);
   RunCodeBaseline(graph, has_result, expected);
 }
 
diff --git a/compiler/optimizing/nodes.cc b/compiler/optimizing/nodes.cc
index 0505510..d624ad5 100644
--- a/compiler/optimizing/nodes.cc
+++ b/compiler/optimizing/nodes.cc
@@ -602,7 +602,11 @@
     int32_t value = Evaluate(GetInput()->AsIntConstant()->GetValue());
     return new(GetBlock()->GetGraph()->GetArena()) HIntConstant(value);
   } else if (GetInput()->IsLongConstant()) {
-    LOG(FATAL) << "Static evaluation of long unary operations is not yet implemented.";
+    // TODO: Implement static evaluation of long unary operations.
+    //
+    // Do not exit with a fatal condition here.  Instead, simply
+    // return `nullptr' to notify the caller that this instruction
+    // cannot (yet) be statically evaluated.
     return nullptr;
   }
   return nullptr;
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index 7c933aa..9b7ff88 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -507,6 +507,7 @@
   M(Neg, UnaryOperation)                                                \
   M(FloatConstant, Constant)                                            \
   M(DoubleConstant, Constant)                                           \
+  M(NewArray, Instruction)                                              \
 
 #define FOR_EACH_INSTRUCTION(M)                                         \
   FOR_EACH_CONCRETE_INSTRUCTION(M)                                      \
@@ -1608,6 +1609,30 @@
   DISALLOW_COPY_AND_ASSIGN(HNeg);
 };
 
+class HNewArray : public HExpression<1> {
+ public:
+  HNewArray(HInstruction* length, uint32_t dex_pc, uint16_t type_index)
+      : HExpression(Primitive::kPrimNot, SideEffects::None()),
+        dex_pc_(dex_pc),
+        type_index_(type_index) {
+    SetRawInputAt(0, length);
+  }
+
+  uint32_t GetDexPc() const { return dex_pc_; }
+  uint16_t GetTypeIndex() const { return type_index_; }
+
+  // Calls runtime so needs an environment.
+  virtual bool NeedsEnvironment() const { return true; }
+
+  DECLARE_INSTRUCTION(NewArray);
+
+ private:
+  const uint32_t dex_pc_;
+  const uint16_t type_index_;
+
+  DISALLOW_COPY_AND_ASSIGN(HNewArray);
+};
+
 class HAdd : public HBinaryOperation {
  public:
   HAdd(Primitive::Type result_type, HInstruction* left, HInstruction* right)
diff --git a/runtime/base/bit_vector.cc b/runtime/base/bit_vector.cc
index 1e0be3a..5b8b6e2 100644
--- a/runtime/base/bit_vector.cc
+++ b/runtime/base/bit_vector.cc
@@ -147,10 +147,7 @@
 
   // Is the storage size smaller than src's?
   if (storage_size_ < union_with_size) {
-    changed = true;
-
-    // Set it to reallocate.
-    SetBit(highest_bit);
+    EnsureSize(highest_bit);
 
     // Paranoid: storage size should be big enough to hold this bit now.
     DCHECK_LT(static_cast<uint32_t> (highest_bit), storage_size_ * kWordBits);
diff --git a/runtime/base/bit_vector_test.cc b/runtime/base/bit_vector_test.cc
index df5d79d..31fd0e7 100644
--- a/runtime/base/bit_vector_test.cc
+++ b/runtime/base/bit_vector_test.cc
@@ -141,4 +141,30 @@
   EXPECT_EQ(64u, bv.NumSetBits());
 }
 
+TEST(BitVector, UnionIfNotIn) {
+  {
+    BitVector first(2, true, Allocator::GetMallocAllocator());
+    BitVector second(5, true, Allocator::GetMallocAllocator());
+    BitVector third(5, true, Allocator::GetMallocAllocator());
+
+    second.SetBit(64);
+    third.SetBit(64);
+    bool changed = first.UnionIfNotIn(&second, &third);
+    EXPECT_EQ(0u, first.NumSetBits());
+    EXPECT_FALSE(changed);
+  }
+
+  {
+    BitVector first(2, true, Allocator::GetMallocAllocator());
+    BitVector second(5, true, Allocator::GetMallocAllocator());
+    BitVector third(5, true, Allocator::GetMallocAllocator());
+
+    second.SetBit(64);
+    bool changed = first.UnionIfNotIn(&second, &third);
+    EXPECT_EQ(1u, first.NumSetBits());
+    EXPECT_TRUE(changed);
+    EXPECT_TRUE(first.IsBitSet(64));
+  }
+}
+
 }  // namespace art
diff --git a/runtime/thread.cc b/runtime/thread.cc
index 32d3129..9c04133 100644
--- a/runtime/thread.cc
+++ b/runtime/thread.cc
@@ -411,6 +411,11 @@
     }
   }
 
+  {
+    ScopedObjectAccess soa(self);
+    Dbg::PostThreadStart(self);
+  }
+
   return self;
 }
 
diff --git a/test/089-many-methods/check b/test/089-many-methods/check
index ec6733d..594626a 100755
--- a/test/089-many-methods/check
+++ b/test/089-many-methods/check
@@ -15,6 +15,6 @@
 # limitations under the License.
 
 # Strip build error debug messages, as they are environment-specific.
-sed -e '/^Failed to build/d' -e '/^Non-canonical tmpdir/d' "$2" > "$2.tmp"
+sed -e '/^Failed to build/d' -e '/^Non-canonical tmpdir/d' -e '/^Args:/d' "$2" > "$2.tmp"
 
 diff --strip-trailing-cr -q "$1" "$2.tmp" >/dev/null
\ No newline at end of file
diff --git a/test/411-optimizing-arith/src/Main.java b/test/411-optimizing-arith/src/Main.java
index 2b3ba33..4de2271 100644
--- a/test/411-optimizing-arith/src/Main.java
+++ b/test/411-optimizing-arith/src/Main.java
@@ -16,7 +16,6 @@
 
 // Note that $opt$ is a marker for the optimizing compiler to ensure
 // it does compile the method.
-
 public class Main {
 
   public static void expectEquals(int expected, int result) {
@@ -31,29 +30,138 @@
     }
   }
 
+  public static void expectEquals(float expected, float result) {
+    if (expected != result) {
+      throw new Error("Expected: " + expected + ", found: " + result);
+    }
+  }
+
+  public static void expectEquals(double expected, double result) {
+    if (expected != result) {
+      throw new Error("Expected: " + expected + ", found: " + result);
+    }
+  }
+
+  public static void expectApproxEquals(float a, float b, float maxDelta) {
+    boolean aproxEquals = (a > b)
+      ? ((a - b) < maxDelta)
+      : ((b - a) < maxDelta);
+    if (!aproxEquals) {
+      throw new Error("Expected: " + a + ", found: " + b + ", with delta: " + maxDelta);
+    }
+  }
+
+  public static void expectApproxEquals(double a, double b, double maxDelta) {
+    boolean aproxEquals = (a > b)
+      ? ((a - b) < maxDelta)
+      : ((b - a) < maxDelta);
+    if (!aproxEquals) {
+      throw new Error("Expected: " + a + ", found: " + b + ", with delta: " + maxDelta);
+    }
+  }
+
+  public static void expectNaN(float a) {
+    if (a == a) {
+      throw new Error("Expected NaN: " + a);
+    }
+  }
+
+  public static void expectNaN(double a) {
+    if (a == a) {
+      throw new Error("Expected NaN: " + a);
+    }
+  }
+
   public static void main(String[] args) {
     mul();
     neg();
   }
 
   public static void mul() {
+    mulInt();
+    mulLong();
+    mulFloat();
+    mulDouble();
+  }
+
+  private static void mulInt() {
     expectEquals(15, $opt$Mul(5, 3));
+    expectEquals(0, $opt$Mul(0, 0));
     expectEquals(0, $opt$Mul(0, 3));
     expectEquals(0, $opt$Mul(3, 0));
     expectEquals(-3, $opt$Mul(1, -3));
     expectEquals(36, $opt$Mul(-12, -3));
     expectEquals(33, $opt$Mul(1, 3) * 11);
     expectEquals(671088645, $opt$Mul(134217729, 5)); // (2^27 + 1) * 5
+  }
 
+  private static void mulLong() {
     expectEquals(15L, $opt$Mul(5L, 3L));
+    expectEquals(0L, $opt$Mul(0L, 0L));
     expectEquals(0L, $opt$Mul(0L, 3L));
     expectEquals(0L, $opt$Mul(3L, 0L));
     expectEquals(-3L, $opt$Mul(1L, -3L));
     expectEquals(36L, $opt$Mul(-12L, -3L));
-    expectEquals(33L, $opt$Mul(1L, 3L) * 11);
+    expectEquals(33L, $opt$Mul(1L, 3L) * 11F);
     expectEquals(240518168583L, $opt$Mul(34359738369L, 7L)); // (2^35 + 1) * 7
+  }
 
-    $opt$InplaceNegOne(1);
+  private static void mulFloat() {
+    expectApproxEquals(15F, $opt$Mul(5F, 3F), 0.0001F);
+    expectApproxEquals(0F, $opt$Mul(0F, 0F), 0.0001F);
+    expectApproxEquals(0F, $opt$Mul(0F, 3F), 0.0001F);
+    expectApproxEquals(0F, $opt$Mul(3F, 0F), 0.0001F);
+    expectApproxEquals(-3F, $opt$Mul(1F, -3F), 0.0001F);
+    expectApproxEquals(36F, $opt$Mul(-12F, -3F), 0.0001F);
+    expectApproxEquals(33F, $opt$Mul(1F, 3F) * 11F, 0.0001F);
+    expectApproxEquals(0.02F, 0.1F * 0.2F, 0.0001F);
+    expectApproxEquals(-0.1F, -0.5F * 0.2F, 0.0001F);
+
+    expectNaN($opt$Mul(0F, Float.POSITIVE_INFINITY));
+    expectNaN($opt$Mul(0F, Float.NEGATIVE_INFINITY));
+    expectNaN($opt$Mul(Float.NaN, 11F));
+    expectNaN($opt$Mul(Float.NaN, -11F));
+    expectNaN($opt$Mul(Float.NaN, Float.NEGATIVE_INFINITY));
+    expectNaN($opt$Mul(Float.NaN, Float.POSITIVE_INFINITY));
+
+    expectEquals(Float.POSITIVE_INFINITY, $opt$Mul(2F, 3.40282346638528860e+38F));
+    expectEquals(Float.POSITIVE_INFINITY, $opt$Mul(2F, Float.POSITIVE_INFINITY));
+    expectEquals(Float.NEGATIVE_INFINITY, $opt$Mul(-2F, Float.POSITIVE_INFINITY));
+    expectEquals(Float.NEGATIVE_INFINITY, $opt$Mul(-2F, 3.40282346638528860e+38F));
+    expectEquals(Float.NEGATIVE_INFINITY, $opt$Mul(2F, Float.NEGATIVE_INFINITY));
+    expectEquals(Float.POSITIVE_INFINITY, $opt$Mul(-2F, Float.NEGATIVE_INFINITY));
+    expectEquals(Float.NEGATIVE_INFINITY, $opt$Mul(Float.POSITIVE_INFINITY, Float.NEGATIVE_INFINITY));
+    expectEquals(Float.POSITIVE_INFINITY, $opt$Mul(Float.POSITIVE_INFINITY, Float.POSITIVE_INFINITY));
+    expectEquals(Float.POSITIVE_INFINITY, $opt$Mul(Float.NEGATIVE_INFINITY, Float.NEGATIVE_INFINITY));
+  }
+
+  private static void mulDouble() {
+    expectApproxEquals(15D, $opt$Mul(5D, 3D), 0.0001D);
+    expectApproxEquals(0D, $opt$Mul(0D, 0D), 0.0001D);
+    expectApproxEquals(0D, $opt$Mul(0D, 3D), 0.0001D);
+    expectApproxEquals(0D, $opt$Mul(3D, 0D), 0.0001D);
+    expectApproxEquals(-3D, $opt$Mul(1D, -3D), 0.0001D);
+    expectApproxEquals(36D, $opt$Mul(-12D, -3D), 0.0001D);
+    expectApproxEquals(33D, $opt$Mul(1D, 3D) * 11D, 0.0001D);
+    expectApproxEquals(0.02D, 0.1D * 0.2D, 0.0001D);
+    expectApproxEquals(-0.1D, -0.5D * 0.2D, 0.0001D);
+
+    expectNaN($opt$Mul(0D, Double.POSITIVE_INFINITY));
+    expectNaN($opt$Mul(0D, Double.NEGATIVE_INFINITY));
+    expectNaN($opt$Mul(Double.NaN, 11D));
+    expectNaN($opt$Mul(Double.NaN, -11D));
+    expectNaN($opt$Mul(Double.NaN, Double.NEGATIVE_INFINITY));
+    expectNaN($opt$Mul(Double.NaN, Double.POSITIVE_INFINITY));
+
+    expectEquals(Double.POSITIVE_INFINITY, $opt$Mul(2D, 1.79769313486231570e+308));
+    expectEquals(Double.POSITIVE_INFINITY, $opt$Mul(2D, Double.POSITIVE_INFINITY));
+    expectEquals(Double.NEGATIVE_INFINITY, $opt$Mul(-2D, Double.POSITIVE_INFINITY));
+    expectEquals(Double.NEGATIVE_INFINITY, $opt$Mul(-2D, 1.79769313486231570e+308));
+    expectEquals(Double.NEGATIVE_INFINITY, $opt$Mul(2D, Double.NEGATIVE_INFINITY));
+    expectEquals(Double.POSITIVE_INFINITY, $opt$Mul(-2D, Double.NEGATIVE_INFINITY));
+    expectEquals(Double.NEGATIVE_INFINITY, $opt$Mul(Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY));
+    expectEquals(Double.POSITIVE_INFINITY, $opt$Mul(Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY));
+    expectEquals(Double.POSITIVE_INFINITY, $opt$Mul(Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY));
   }
 
   public static void neg() {
@@ -75,6 +183,8 @@
     //   Overflow occurs in this case, but no exception is thrown.
     //   For all integer values x, -x equals (~x)+1.''
     expectEquals(-2147483648, $opt$Neg(-2147483648)); // -(2^31)
+
+    $opt$InplaceNegOne(1);
   }
 
   public static void $opt$InplaceNegOne(int a) {
@@ -90,7 +200,16 @@
     return a * b;
   }
 
+  static float $opt$Mul(float a, float b) {
+    return a * b;
+  }
+
+  static double $opt$Mul(double a, double b) {
+    return a * b;
+  }
+
   static int $opt$Neg(int a){
     return -a;
   }
+
 }
diff --git a/test/412-new-array/expected.txt b/test/412-new-array/expected.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/412-new-array/expected.txt
diff --git a/test/412-new-array/info.txt b/test/412-new-array/info.txt
new file mode 100644
index 0000000..cb388b6
--- /dev/null
+++ b/test/412-new-array/info.txt
@@ -0,0 +1 @@
+Simple tests for new-array, filled-new-array and fill-array-data.
diff --git a/test/412-new-array/smali/fill_array_data.smali b/test/412-new-array/smali/fill_array_data.smali
new file mode 100644
index 0000000..34776db
--- /dev/null
+++ b/test/412-new-array/smali/fill_array_data.smali
@@ -0,0 +1,81 @@
+.class public LFillArrayData;
+
+.super Ljava/lang/Object;
+
+.method public static intArray([I)V
+   .registers 1
+
+   fill-array-data v0, :ArrayData
+   return-void
+
+:ArrayData
+    .array-data 4
+        1 2 3 4 5
+    .end array-data
+
+.end method
+
+.method public static shortArray([S)V
+   .registers 1
+
+   fill-array-data v0, :ArrayData
+   return-void
+
+:ArrayData
+    .array-data 2
+        1 2 3 4 5
+    .end array-data
+
+.end method
+
+.method public static charArray([C)V
+   .registers 1
+
+   fill-array-data v0, :ArrayData
+   return-void
+
+:ArrayData
+    .array-data 2
+        1 2 3 4 5
+    .end array-data
+
+.end method
+
+.method public static byteArray([B)V
+   .registers 1
+
+   fill-array-data v0, :ArrayData
+   return-void
+
+:ArrayData
+    .array-data 1
+        1 2 3 4 5
+    .end array-data
+
+.end method
+
+.method public static booleanArray([Z)V
+   .registers 1
+
+   fill-array-data v0, :ArrayData
+   return-void
+
+:ArrayData
+    .array-data 1
+        0 1 1
+    .end array-data
+
+.end method
+
+.method public static longArray([J)V
+   .registers 1
+
+   fill-array-data v0, :ArrayData
+   return-void
+
+:ArrayData
+    .array-data 8
+        1 2 3 4 5
+    .end array-data
+
+.end method
diff --git a/test/412-new-array/smali/filled_new_array.smali b/test/412-new-array/smali/filled_new_array.smali
new file mode 100644
index 0000000..ed8683a
--- /dev/null
+++ b/test/412-new-array/smali/filled_new_array.smali
@@ -0,0 +1,45 @@
+.class public LFilledNewArray;
+
+.super Ljava/lang/Object;
+
+.method public static newInt(III)[I
+   .registers 4
+   filled-new-array {v1, v2, v3}, [I
+   move-result-object v0
+   return-object v0
+.end method
+
+.method public static newRef(Ljava/lang/Object;Ljava/lang/Object;)[Ljava/lang/Object;
+   .registers 3
+   filled-new-array {v1, v2}, [Ljava/lang/Object;
+   move-result-object v0
+   return-object v0
+.end method
+
+.method public static newArray([I[I)[[I
+   .registers 3
+   filled-new-array {v1, v2}, [[I
+   move-result-object v0
+   return-object v0
+.end method
+
+.method public static newIntRange(III)[I
+   .registers 4
+   filled-new-array/range {v1 .. v3}, [I
+   move-result-object v0
+   return-object v0
+.end method
+
+.method public static newRefRange(Ljava/lang/Object;Ljava/lang/Object;)[Ljava/lang/Object;
+   .registers 3
+   filled-new-array/range {v1 .. v2}, [Ljava/lang/Object;
+   move-result-object v0
+   return-object v0
+.end method
+
+.method public static newArrayRange([I[I)[[I
+   .registers 3
+   filled-new-array/range {v1 .. v2}, [[I
+   move-result-object v0
+   return-object v0
+.end method
diff --git a/test/412-new-array/smali/filled_new_array_verify_error.smali b/test/412-new-array/smali/filled_new_array_verify_error.smali
new file mode 100644
index 0000000..b1470ec
--- /dev/null
+++ b/test/412-new-array/smali/filled_new_array_verify_error.smali
@@ -0,0 +1,10 @@
+.class public LFilledNewArrayVerifyError;
+
+.super Ljava/lang/Object;
+
+.method public static newRef(Ljava/lang/Object;Ljava/lang/Object;)[Ljava/lang/Object;
+   .registers 3
+   filled-new-array {v1, v2}, [Ljava/lang/Integer;
+   move-result-object v0
+   return-object v0
+.end method
diff --git a/test/412-new-array/src/Main.java b/test/412-new-array/src/Main.java
new file mode 100644
index 0000000..3c74275
--- /dev/null
+++ b/test/412-new-array/src/Main.java
@@ -0,0 +1,418 @@
+/*
+ * Copyright (C) 2014 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.
+ */
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+// Note that $opt$ is a marker for the optimizing compiler to ensure
+// it does compile the method.
+
+public class Main extends TestCase {
+  public static void main(String[] args) throws Exception {
+    $opt$TestAllocations();
+    $opt$TestWithInitializations();
+    testSmaliFilledNewArray();
+    testSmaliFillArrayData();
+    testSmaliVerifyError();
+  }
+
+  static void $opt$TestAllocations() {
+    float[] a = new float[1];
+    assertEquals(1, a.length);
+
+    double[] b = new double[2];
+    assertEquals(2, b.length);
+
+    long[] c = new long[3];
+    assertEquals(3, c.length);
+
+    int[] d = new int[4];
+    assertEquals(4, d.length);
+
+    short[] e = new short[5];
+    assertEquals(5, e.length);
+
+    char[] f = new char[6];
+    assertEquals(6, f.length);
+
+    byte[] g = new byte[7];
+    assertEquals(7, g.length);
+
+    boolean[] h = new boolean[8];
+    assertEquals(8, h.length);
+
+    Object[] i = new Object[9];
+    assertEquals(9, i.length);
+  }
+
+  static void $opt$TestWithInitializations() {
+    float[] a = { 1.2f };
+    assertEquals(1, a.length);
+    assertEquals(1.2f, a[0]);
+
+    double[] b = { 4.3, 1.2 };
+    assertEquals(2, b.length);
+    assertEquals(4.3, b[0]);
+    assertEquals(1.2, b[1]);
+
+    long[] c = { 4L, 5L };
+    assertEquals(2, c.length);
+    assertEquals(4L, c[0]);
+    assertEquals(5L, c[1]);
+
+    int[] d = {1, 2, 3};
+    assertEquals(3, d.length);
+    assertEquals(1, d[0]);
+    assertEquals(2, d[1]);
+    assertEquals(3, d[2]);
+
+    short[] e = {4, 5, 6};
+    assertEquals(3, e.length);
+    assertEquals(4, e[0]);
+    assertEquals(5, e[1]);
+    assertEquals(6, e[2]);
+
+    char[] f = {'a', 'b'};
+    assertEquals(2, f.length);
+    assertEquals('a', f[0]);
+    assertEquals('b', f[1]);
+
+    byte[] g = {7, 8, 9};
+    assertEquals(3, g.length);
+    assertEquals(7, g[0]);
+    assertEquals(8, g[1]);
+    assertEquals(9, g[2]);
+
+    boolean[] h = {true, false};
+    assertEquals(2, h.length);
+    assertEquals(true, h[0]);
+    assertEquals(false, h[1]);
+
+    Object obj1 = new Object();
+    Object obj2 = new Object();
+    Object[] i = {obj1, obj2};
+    assertEquals(2, i.length);
+    assertEquals(obj1, i[0]);
+    assertEquals(obj2, i[1]);
+  }
+
+  public static void testSmaliFilledNewArray() throws Exception {
+    Class<?> c = Class.forName("FilledNewArray");
+
+    {
+      Method m = c.getMethod("newInt", Integer.TYPE, Integer.TYPE, Integer.TYPE);
+      Object[] args = {new Integer(1), new Integer(2), new Integer(3)};
+      int[] result = (int[])m.invoke(null, args);
+      assertEquals(3, result.length);
+      assertEquals(1, result[0]);
+      assertEquals(2, result[1]);
+      assertEquals(3, result[2]);
+    }
+
+    {
+      Method m = c.getMethod("newRef", Object.class, Object.class);
+      Object[] args = {new Integer(1), new Integer(2)};
+      Object[] result = (Object[])m.invoke(null, args);
+      assertEquals(2, result.length);
+      assertEquals(args[0], result[0]);
+      assertEquals(args[1], result[1]);
+    }
+
+    {
+      Method m = c.getMethod("newArray", int[].class, int[].class);
+      Object[] args = {new int[0], new int[1]};
+      Object[] result = (Object[])m.invoke(null, args);
+      assertEquals(2, result.length);
+      assertEquals(args[0], result[0]);
+      assertEquals(args[1], result[1]);
+    }
+
+    {
+      Method m = c.getMethod("newIntRange", Integer.TYPE, Integer.TYPE, Integer.TYPE);
+      Object[] args = {new Integer(1), new Integer(2), new Integer(3)};
+      int[] result = (int[])m.invoke(null, args);
+      assertEquals(3, result.length);
+      assertEquals(1, result[0]);
+      assertEquals(2, result[1]);
+      assertEquals(3, result[2]);
+    }
+
+    {
+      Method m = c.getMethod("newRefRange", Object.class, Object.class);
+      Object[] args = {new Integer(1), new Integer(2)};
+      Object[] result = (Object[])m.invoke(null, args);
+      assertEquals(2, result.length);
+      assertEquals(args[0], result[0]);
+      assertEquals(args[1], result[1]);
+    }
+
+    {
+      Method m = c.getMethod("newArrayRange", int[].class, int[].class);
+      Object[] args = {new int[0], new int[1]};
+      Object[] result = (Object[])m.invoke(null, args);
+      assertEquals(2, result.length);
+      assertEquals(args[0], result[0]);
+      assertEquals(args[1], result[1]);
+    }
+  }
+
+  public static void testSmaliVerifyError() throws Exception {
+    Error error = null;
+    // Ensure the elements in filled-new-array must be assignable
+    // to the array component type.
+    try {
+      Class.forName("FilledNewArrayVerifyError");
+    } catch (VerifyError e) {
+      error = e;
+    }
+    assertNotNull(error);
+  }
+
+  public static void testSmaliFillArrayData() throws Exception {
+    Class<?> c = Class.forName("FillArrayData");
+    {
+      Method m = c.getMethod("intArray", int[].class);
+      int[] array = new int[7];
+      Object[] args = { array };
+      m.invoke(null, args);
+      assertEquals(7, array.length);
+      assertEquals(1, array[0]);
+      assertEquals(2, array[1]);
+      assertEquals(3, array[2]);
+      assertEquals(4, array[3]);
+      assertEquals(5, array[4]);
+      assertEquals(0, array[5]);
+      assertEquals(0, array[6]);
+
+      array = new int[2];
+      args[0] = array;
+      Throwable exception  = null;
+      try {
+        m.invoke(null, args);
+      } catch (InvocationTargetException e) {
+        exception = e.getCause();
+        assertTrue(exception instanceof IndexOutOfBoundsException);
+      }
+      assertNotNull(exception);
+      exception = null;
+      // Test that nothing has been written to the array.
+      assertEquals(0, array[0]);
+      assertEquals(0, array[1]);
+
+      args[0] = null;
+      try {
+        m.invoke(null, args);
+      } catch (InvocationTargetException e) {
+        exception = e.getCause();
+        assertTrue(exception instanceof NullPointerException);
+      }
+      assertNotNull(exception);
+    }
+
+    {
+      Method m = c.getMethod("shortArray", short[].class);
+      short[] array = new short[7];
+      Object[] args = { array };
+      m.invoke(null, args);
+      assertEquals(7, array.length);
+      assertEquals(1, array[0]);
+      assertEquals(2, array[1]);
+      assertEquals(3, array[2]);
+      assertEquals(4, array[3]);
+      assertEquals(5, array[4]);
+      assertEquals(0, array[5]);
+      assertEquals(0, array[6]);
+
+      array = new short[2];
+      args[0] = array;
+      Throwable exception  = null;
+      try {
+        m.invoke(null, args);
+      } catch (InvocationTargetException e) {
+        exception = e.getCause();
+        assertTrue(exception instanceof IndexOutOfBoundsException);
+      }
+      assertNotNull(exception);
+      exception = null;
+      // Test that nothing has been written to the array.
+      assertEquals(0, array[0]);
+      assertEquals(0, array[1]);
+
+      args[0] = null;
+      try {
+        m.invoke(null, args);
+      } catch (InvocationTargetException e) {
+        exception = e.getCause();
+        assertTrue(exception instanceof NullPointerException);
+      }
+      assertNotNull(exception);
+    }
+
+    {
+      Method m = c.getMethod("longArray", long[].class);
+      long[] array = new long[7];
+      Object[] args = { array };
+      m.invoke(null, args);
+      assertEquals(7, array.length);
+      assertEquals(1L, array[0]);
+      assertEquals(2L, array[1]);
+      assertEquals(3L, array[2]);
+      assertEquals(4L, array[3]);
+      assertEquals(5L, array[4]);
+      assertEquals(0L, array[5]);
+      assertEquals(0L, array[6]);
+
+      array = new long[2];
+      args[0] = array;
+      Throwable exception  = null;
+      try {
+        m.invoke(null, args);
+      } catch (InvocationTargetException e) {
+        exception = e.getCause();
+        assertTrue(exception instanceof IndexOutOfBoundsException);
+      }
+      assertNotNull(exception);
+      exception = null;
+      // Test that nothing has been written to the array.
+      assertEquals(0, array[0]);
+      assertEquals(0, array[1]);
+
+      args[0] = null;
+      try {
+        m.invoke(null, args);
+      } catch (InvocationTargetException e) {
+        exception = e.getCause();
+        assertTrue(exception instanceof NullPointerException);
+      }
+      assertNotNull(exception);
+    }
+
+    {
+      Method m = c.getMethod("charArray", char[].class);
+      char[] array = new char[7];
+      Object[] args = { array };
+      m.invoke(null, args);
+      assertEquals(7, array.length);
+      assertEquals(1, array[0]);
+      assertEquals(2, array[1]);
+      assertEquals(3, array[2]);
+      assertEquals(4, array[3]);
+      assertEquals(5, array[4]);
+      assertEquals(0, array[5]);
+      assertEquals(0, array[6]);
+
+      array = new char[2];
+      args[0] = array;
+      Throwable exception  = null;
+      try {
+        m.invoke(null, args);
+      } catch (InvocationTargetException e) {
+        exception = e.getCause();
+        assertTrue(exception instanceof IndexOutOfBoundsException);
+      }
+      assertNotNull(exception);
+      exception = null;
+      // Test that nothing has been written to the array.
+      assertEquals(0, array[0]);
+      assertEquals(0, array[1]);
+
+      args[0] = null;
+      try {
+        m.invoke(null, args);
+      } catch (InvocationTargetException e) {
+        exception = e.getCause();
+        assertTrue(exception instanceof NullPointerException);
+      }
+      assertNotNull(exception);
+    }
+
+    {
+      Method m = c.getMethod("byteArray", byte[].class);
+      byte[] array = new byte[7];
+      Object[] args = { array };
+      m.invoke(null, args);
+      assertEquals(7, array.length);
+      assertEquals(1, array[0]);
+      assertEquals(2, array[1]);
+      assertEquals(3, array[2]);
+      assertEquals(4, array[3]);
+      assertEquals(5, array[4]);
+      assertEquals(0, array[5]);
+      assertEquals(0, array[6]);
+
+      array = new byte[2];
+      args[0] = array;
+      Throwable exception  = null;
+      try {
+        m.invoke(null, args);
+      } catch (InvocationTargetException e) {
+        exception = e.getCause();
+        assertTrue(exception instanceof IndexOutOfBoundsException);
+      }
+      assertNotNull(exception);
+      exception = null;
+      // Test that nothing has been written to the array.
+      assertEquals(0, array[0]);
+      assertEquals(0, array[1]);
+
+      args[0] = null;
+      try {
+        m.invoke(null, args);
+      } catch (InvocationTargetException e) {
+        exception = e.getCause();
+        assertTrue(exception instanceof NullPointerException);
+      }
+      assertNotNull(exception);
+    }
+
+    {
+      Method m = c.getMethod("booleanArray", boolean[].class);
+      boolean[] array = new boolean[5];
+      Object[] args = { array };
+      m.invoke(null, args);
+      assertEquals(5, array.length);
+      assertEquals(false, array[0]);
+      assertEquals(true, array[1]);
+      assertEquals(true, array[2]);
+      assertEquals(false, array[3]);
+      assertEquals(false, array[4]);
+
+      array = new boolean[2];
+      args[0] = array;
+      Throwable exception  = null;
+      try {
+        m.invoke(null, args);
+      } catch (InvocationTargetException e) {
+        exception = e.getCause();
+        assertTrue(exception instanceof IndexOutOfBoundsException);
+      }
+      assertNotNull(exception);
+      exception = null;
+      // Test that nothing has been written to the array.
+      assertEquals(false, array[0]);
+      assertEquals(false, array[1]);
+
+      args[0] = null;
+      try {
+        m.invoke(null, args);
+      } catch (InvocationTargetException e) {
+        exception = e.getCause();
+        assertTrue(exception instanceof NullPointerException);
+      }
+      assertNotNull(exception);
+    }
+  }
+}
diff --git a/test/412-new-array/src/TestCase.java b/test/412-new-array/src/TestCase.java
new file mode 100644
index 0000000..ef77f71
--- /dev/null
+++ b/test/412-new-array/src/TestCase.java
@@ -0,0 +1,199 @@
+/*
+ * Copyright (C) 2014 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.
+ */
+
+/**
+ * Common superclass for test cases.
+ */
+
+import java.util.Arrays;
+
+public abstract class TestCase {
+  public static void assertSame(Object expected, Object value) {
+    if (expected != value) {
+      throw new AssertionError("Objects are not the same: expected " +
+          String.valueOf(expected) + ", got " + String.valueOf(value));
+    }
+  }
+
+  public static void assertNotSame(Object expected, Object value) {
+    if (expected == value) {
+      throw new AssertionError(
+          "Objects are the same: " + String.valueOf(expected));
+    }
+  }
+
+  public static void assertEquals(String message, int expected, int actual) {
+    if (expected != actual) {
+      throw new AssertionError(message);
+    }
+  }
+
+  public static void assertEquals(int expected, int actual) {
+    if (expected != actual) {
+      throw new AssertionError("Expected " + expected + " got " + actual);
+    }
+  }
+
+  public static void assertTrue(String message, boolean condition) {
+    if (!condition) {
+      throw new AssertionError(message);
+    }
+  }
+
+  public static void assertTrue(boolean condition) {
+    assertTrue("Expected true", condition);
+  }
+
+  public static void assertFalse(String message, boolean condition) {
+    if (condition) {
+      throw new AssertionError(message);
+    }
+  }
+
+  public static void assertFalse(boolean condition) {
+    assertFalse("Expected false", condition);
+  }
+
+  public static void assertEquals(Object expected, Object actual) {
+    if (!expected.equals(actual)) {
+      String msg = "Expected \"" + expected + "\" but got \"" + actual + "\"";
+      throw new AssertionError(msg);
+    }
+  }
+
+  public static void assertNotEquals(int expected, int actual) {
+    if (expected == actual) {
+      throw new AssertionError("Expected " + expected + " got " + actual);
+    }
+  }
+
+  public static void assertNotEquals(Object expected, Object actual) {
+    if (expected.equals(actual)) {
+      String msg = "Objects are the same: " + String.valueOf(expected);
+      throw new AssertionError(msg);
+    }
+  }
+
+  public static <T> void assertArrayEquals(T[] actual, T... expected) {
+      assertTrue(Arrays.equals(expected, actual));
+  }
+
+  public static void assertEquals(
+      String message, Object expected, Object actual) {
+    if (!expected.equals(actual)) {
+      throw new AssertionError(message);
+    }
+  }
+
+  public static void assertEquals(
+      String message, long expected, long actual) {
+    if (expected != actual) {
+      throw new AssertionError(message);
+    }
+  }
+
+  public static void assertEquals(long expected, long actual) {
+    if (expected != actual) {
+      throw new AssertionError("Expected " + expected + " got " + actual);
+    }
+  }
+
+  public static void assertEquals(
+      String message, boolean expected, boolean actual) {
+    if (expected != actual) {
+      throw new AssertionError(message);
+    }
+  }
+
+  public static void assertEquals(boolean expected, boolean actual) {
+    if (expected != actual) {
+      throw new AssertionError("Expected " + expected + " got " + actual);
+    }
+  }
+
+  public static void assertEquals(
+      String message, float expected, float actual) {
+    if (expected != actual) {
+      throw new AssertionError(message);
+    }
+  }
+
+  public static void assertEquals(float expected, float actual) {
+    if (expected != actual) {
+      throw new AssertionError("Expected " + expected + " got " + actual);
+    }
+  }
+
+  public static void assertEquals(float expected, float actual,
+                                  float tolerance) {
+    if ((actual < expected - tolerance) || (expected + tolerance < actual)) {
+      throw new AssertionError("Expected " + expected + " got " + actual +
+          " tolerance " + tolerance);
+    }
+  }
+
+  public static void assertEquals(
+      String message, double expected, double actual) {
+    if (expected != actual) {
+      throw new AssertionError(message);
+    }
+  }
+
+  public static void assertEquals(double expected, double actual) {
+    if (expected != actual) {
+      throw new AssertionError("Expected " + expected + " got " + actual);
+    }
+  }
+
+  public static void assertEquals(double expected, double actual,
+                                  double tolerance) {
+    if ((actual < expected - tolerance) || (expected + tolerance < actual)) {
+      throw new AssertionError("Expected " + expected + " got " + actual +
+          " tolerance " + tolerance);
+    }
+  }
+
+  public static void assertSame(
+      String message, Object expected, Object actual) {
+    if (expected != actual) {
+      throw new AssertionError(message);
+    }
+  }
+
+  public static void assertNull(String message, Object object) {
+    if (object != null) {
+      throw new AssertionError(message);
+    }
+  }
+
+  public static void assertNull(Object object) {
+    assertNull("Expected null", object);
+  }
+
+  public static void assertNotNull(String message, Object object) {
+    if (object == null) {
+      throw new AssertionError(message);
+    }
+  }
+
+  public static void assertNotNull(Object object) {
+    assertNotNull("Expected non-null", object);
+  }
+
+  public static void fail(String msg) {
+    throw new AssertionError(msg);
+  }
+}
diff --git a/test/Android.run-test.mk b/test/Android.run-test.mk
index 97afd00..427e0b1 100644
--- a/test/Android.run-test.mk
+++ b/test/Android.run-test.mk
@@ -66,11 +66,6 @@
 ########################################################################
 # General rules to build and run a run-test.
 
-# Test rule names or of the form:
-# test-art-{1: host or target}-run-test-{2: prebuild no-prebuild no-dex2oat}-
-#    {3: interpreter default optimizing}-{4: relocate no-relocate relocate-no-patchoat}-
-#    {5: trace or no-trace}-{6: gcstress gcverify cms}-{7: forcecopy checkjni jni}-
-#    {8: no-image or image}-{9: test name}{10: 32 or 64}
 TARGET_TYPES := host target
 PREBUILD_TYPES := prebuild
 ifeq ($(ART_TEST_RUN_TEST_NO_PREBUILD),true)
@@ -283,6 +278,18 @@
 
 TEST_ART_BROKEN_NDEBUG_TESTS :=
 
+# Known broken tests for the default compiler (Quick).
+TEST_ART_BROKEN_DEFAULT_RUN_TESTS := \
+  412-new-array
+
+ifneq (,$(filter default,$(COMPILER_TYPES)))
+  ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,$(TARGET_TYPES),$(RUN_TYPES),$(PREBUILD_TYPES), \
+      default,$(RELOCATE_TYPES),$(TRACE_TYPES),$(GC_TYPES),$(JNI_TYPES), \
+      $(IMAGE_TYPES),$(TEST_ART_BROKEN_DEFAULT_RUN_TESTS),$(ALL_ADDRESS_SIZES))
+endif
+
+TEST_ART_BROKEN_DEFAULT_RUN_TESTS :=
+
 # Clear variables ahead of appending to them when defining tests.
 $(foreach target, $(TARGET_TYPES), $(eval ART_RUN_TEST_$(call name-to-var,$(target))_RULES :=))
 $(foreach target, $(TARGET_TYPES), \
@@ -348,7 +355,7 @@
 endif
 
 # Create a rule to build and run a tests following the form:
-# test-art-{1: host or target}-run-test-{2:debug ndebug}-{3: prebuild no-prebuild no-dex2oat}-
+# test-art-{1: host or target}-run-test-{2: debug ndebug}-{3: prebuild no-prebuild no-dex2oat}-
 #    {4: interpreter default optimizing}-{5: relocate no-relocate relocate-no-patchoat}-
 #    {6: trace or no-trace}-{7: gcstress gcverify cms}-{8: forcecopy checkjni jni}-
 #    {9: no-image image}-{10: test name}{11: 32 or 64}
diff --git a/test/etc/default-build b/test/etc/default-build
index faafc1f..009736b 100755
--- a/test/etc/default-build
+++ b/test/etc/default-build
@@ -26,7 +26,12 @@
 
 if [ ${NEED_DEX} = "true" ]; then
   ${DX} -JXmx256m --debug --dex --dump-to=classes.lst --output=classes.dex --dump-width=1000 classes
-  zip $TEST_NAME.jar classes.dex
+fi
+
+if [ -r smali ]; then
+  # Compile Smali classes
+  ${SMALI} -JXmx256m --output smali_classes.dex `find smali -name '*.smali'`
+  ${DXMERGER} classes.dex classes.dex smali_classes.dex
 fi
 
 if [ -r src-ex ]; then
@@ -43,3 +48,5 @@
     mv classes-1.dex classes.dex
   fi
 fi
+
+zip $TEST_NAME.jar classes.dex
diff --git a/test/run-test b/test/run-test
index 36288d7..73ffc31 100755
--- a/test/run-test
+++ b/test/run-test
@@ -17,6 +17,7 @@
 # Set up prog to be the path of this script, including following symlinks,
 # and set up progdir to be the fully-qualified pathname of its directory.
 prog="$0"
+args="$@"
 while [ -h "${prog}" ]; do
     newProg=`/bin/ls -ld "${prog}"`
     newProg=`expr "${newProg}" : ".* -> \(.*\)$"`
@@ -528,6 +529,7 @@
         cp "$build_output" "$output"
         echo "Failed to build in tmpdir=${tmp_dir} from oldwd=${oldwd} and cwd=`pwd`" >> "$output"
         echo "Non-canonical tmpdir was ${noncanonical_tmp_dir}" >> "$output"
+        echo "Args: ${args}" >> "output"
         echo "build exit status: $build_exit" >> "$output"
     fi
     ./$check_cmd "$expected" "$output"