| Index: runtime/vm/simulator_arm.cc
 | 
| ===================================================================
 | 
| --- runtime/vm/simulator_arm.cc	(revision 36258)
 | 
| +++ runtime/vm/simulator_arm.cc	(working copy)
 | 
| @@ -676,60 +676,9 @@
 | 
|  }
 | 
|  
 | 
|  
 | 
| -// Synchronization primitives support.
 | 
| -Mutex* Simulator::exclusive_access_lock_ = NULL;
 | 
| -Simulator::AddressTag Simulator::exclusive_access_state_[kNumAddressTags];
 | 
| -int Simulator::next_address_tag_;
 | 
| +void Simulator::InitOnce() {}
 | 
|  
 | 
|  
 | 
| -void Simulator::SetExclusiveAccess(uword addr) {
 | 
| -  Isolate* isolate = Isolate::Current();
 | 
| -  ASSERT(isolate != NULL);
 | 
| -  int i = 0;
 | 
| -  while ((i < kNumAddressTags) &&
 | 
| -         (exclusive_access_state_[i].isolate != isolate)) {
 | 
| -    i++;
 | 
| -  }
 | 
| -  if (i == kNumAddressTags) {
 | 
| -    i = next_address_tag_;
 | 
| -    if (++next_address_tag_ == kNumAddressTags) next_address_tag_ = 0;
 | 
| -    exclusive_access_state_[i].isolate = isolate;
 | 
| -  }
 | 
| -  exclusive_access_state_[i].addr = addr;
 | 
| -}
 | 
| -
 | 
| -
 | 
| -bool Simulator::HasExclusiveAccessAndOpen(uword addr) {
 | 
| -  Isolate* isolate = Isolate::Current();
 | 
| -  ASSERT(isolate != NULL);
 | 
| -  bool result = false;
 | 
| -  for (int i = 0; i < kNumAddressTags; i++) {
 | 
| -    if (exclusive_access_state_[i].isolate == isolate) {
 | 
| -      if (exclusive_access_state_[i].addr == addr) {
 | 
| -        result = true;
 | 
| -      }
 | 
| -      exclusive_access_state_[i].addr = static_cast<uword>(NULL);
 | 
| -      continue;
 | 
| -    }
 | 
| -    if (exclusive_access_state_[i].addr == addr) {
 | 
| -      exclusive_access_state_[i].addr = static_cast<uword>(NULL);
 | 
| -    }
 | 
| -  }
 | 
| -  return result;
 | 
| -}
 | 
| -
 | 
| -
 | 
| -void Simulator::InitOnce() {
 | 
| -  // Setup exclusive access state.
 | 
| -  exclusive_access_lock_ = new Mutex();
 | 
| -  for (int i = 0; i < kNumAddressTags; i++) {
 | 
| -    exclusive_access_state_[i].isolate = NULL;
 | 
| -    exclusive_access_state_[i].addr = static_cast<uword>(NULL);
 | 
| -  }
 | 
| -  next_address_tag_ = 0;
 | 
| -}
 | 
| -
 | 
| -
 | 
|  Simulator::Simulator() {
 | 
|    // Setup simulator support first. Some of this information is needed to
 | 
|    // setup the architecture state.
 | 
| @@ -907,30 +856,35 @@
 | 
|  
 | 
|  // Accessors for VFP register state.
 | 
|  void Simulator::set_sregister(SRegister reg, float value) {
 | 
| +  ASSERT(TargetCPUFeatures::vfp_supported());
 | 
|    ASSERT((reg >= 0) && (reg < kNumberOfSRegisters));
 | 
|    sregisters_[reg] = bit_cast<int32_t, float>(value);
 | 
|  }
 | 
|  
 | 
|  
 | 
|  float Simulator::get_sregister(SRegister reg) const {
 | 
| +  ASSERT(TargetCPUFeatures::vfp_supported());
 | 
|    ASSERT((reg >= 0) && (reg < kNumberOfSRegisters));
 | 
|    return bit_cast<float, int32_t>(sregisters_[reg]);
 | 
|  }
 | 
|  
 | 
|  
 | 
|  void Simulator::set_dregister(DRegister reg, double value) {
 | 
| +  ASSERT(TargetCPUFeatures::vfp_supported());
 | 
|    ASSERT((reg >= 0) && (reg < kNumberOfDRegisters));
 | 
|    dregisters_[reg] = bit_cast<int64_t, double>(value);
 | 
|  }
 | 
|  
 | 
|  
 | 
|  double Simulator::get_dregister(DRegister reg) const {
 | 
| +  ASSERT(TargetCPUFeatures::vfp_supported());
 | 
|    ASSERT((reg >= 0) && (reg < kNumberOfDRegisters));
 | 
|    return bit_cast<double, int64_t>(dregisters_[reg]);
 | 
|  }
 | 
|  
 | 
|  
 | 
|  void Simulator::set_qregister(QRegister reg, const simd_value_t& value) {
 | 
| +  ASSERT(TargetCPUFeatures::neon_supported());
 | 
|    ASSERT((reg >= 0) && (reg < kNumberOfQRegisters));
 | 
|    qregisters_[reg].data_[0] = value.data_[0];
 | 
|    qregisters_[reg].data_[1] = value.data_[1];
 | 
| @@ -940,6 +894,7 @@
 | 
|  
 | 
|  
 | 
|  void Simulator::get_qregister(QRegister reg, simd_value_t* value) const {
 | 
| +  ASSERT(TargetCPUFeatures::neon_supported());
 | 
|    // TODO(zra): Replace this test with an assert after we support
 | 
|    // 16 Q registers.
 | 
|    if ((reg >= 0) && (reg < kNumberOfQRegisters)) {
 | 
| @@ -949,24 +904,28 @@
 | 
|  
 | 
|  
 | 
|  void Simulator::set_sregister_bits(SRegister reg, int32_t value) {
 | 
| +  ASSERT(TargetCPUFeatures::vfp_supported());
 | 
|    ASSERT((reg >= 0) && (reg < kNumberOfSRegisters));
 | 
|    sregisters_[reg] = value;
 | 
|  }
 | 
|  
 | 
|  
 | 
|  int32_t Simulator::get_sregister_bits(SRegister reg) const {
 | 
| +  ASSERT(TargetCPUFeatures::vfp_supported());
 | 
|    ASSERT((reg >= 0) && (reg < kNumberOfSRegisters));
 | 
|    return sregisters_[reg];
 | 
|  }
 | 
|  
 | 
|  
 | 
|  void Simulator::set_dregister_bits(DRegister reg, int64_t value) {
 | 
| +  ASSERT(TargetCPUFeatures::vfp_supported());
 | 
|    ASSERT((reg >= 0) && (reg < kNumberOfDRegisters));
 | 
|    dregisters_[reg] = value;
 | 
|  }
 | 
|  
 | 
|  
 | 
|  int64_t Simulator::get_dregister_bits(DRegister reg) const {
 | 
| +  ASSERT(TargetCPUFeatures::vfp_supported());
 | 
|    ASSERT((reg >= 0) && (reg < kNumberOfDRegisters));
 | 
|    return dregisters_[reg];
 | 
|  }
 | 
| @@ -1101,53 +1060,6 @@
 | 
|  }
 | 
|  
 | 
|  
 | 
| -// Synchronization primitives support.
 | 
| -void Simulator::ClearExclusive() {
 | 
| -  // This lock is initialized in Simulator::InitOnce().
 | 
| -  MutexLocker ml(exclusive_access_lock_);
 | 
| -  // Set exclusive access to open state for this isolate.
 | 
| -  HasExclusiveAccessAndOpen(static_cast<uword>(NULL));
 | 
| -}
 | 
| -
 | 
| -
 | 
| -intptr_t Simulator::ReadExclusiveW(uword addr, Instr* instr) {
 | 
| -  // This lock is initialized in Simulator::InitOnce().
 | 
| -  MutexLocker ml(exclusive_access_lock_);
 | 
| -  SetExclusiveAccess(addr);
 | 
| -  return ReadW(addr, instr);
 | 
| -}
 | 
| -
 | 
| -
 | 
| -intptr_t Simulator::WriteExclusiveW(uword addr, intptr_t value, Instr* instr) {
 | 
| -  // This lock is initialized in Simulator::InitOnce().
 | 
| -  MutexLocker ml(exclusive_access_lock_);
 | 
| -  bool write_allowed = HasExclusiveAccessAndOpen(addr);
 | 
| -  if (write_allowed) {
 | 
| -    WriteW(addr, value, instr);
 | 
| -    return 0;  // Success.
 | 
| -  }
 | 
| -  return 1;  // Failure.
 | 
| -}
 | 
| -
 | 
| -
 | 
| -uword Simulator::CompareExchange(uword* address,
 | 
| -                                 uword compare_value,
 | 
| -                                 uword new_value) {
 | 
| -  // This lock is initialized in Simulator::InitOnce().
 | 
| -  MutexLocker ml(exclusive_access_lock_);
 | 
| -  uword value = *address;
 | 
| -  if (value == compare_value) {
 | 
| -    *address = new_value;
 | 
| -    // Same effect on exclusive access state as a successful STREX.
 | 
| -    HasExclusiveAccessAndOpen(reinterpret_cast<uword>(address));
 | 
| -  } else {
 | 
| -    // Same effect on exclusive access state as an LDREX.
 | 
| -    SetExclusiveAccess(reinterpret_cast<uword>(address));
 | 
| -  }
 | 
| -  return value;
 | 
| -}
 | 
| -
 | 
| -
 | 
|  // Returns the top of the stack area to enable checking for stack pointer
 | 
|  // validity.
 | 
|  uword Simulator::StackTop() const {
 | 
| @@ -1597,18 +1509,20 @@
 | 
|          set_register(R3, icount_);
 | 
|          set_register(IP, icount_);
 | 
|          set_register(LR, icount_);
 | 
| -        double zap_dvalue = static_cast<double>(icount_);
 | 
| -        // Do not zap D0, as it may contain a float result.
 | 
| -        for (int i = D1; i <= D7; i++) {
 | 
| -          set_dregister(static_cast<DRegister>(i), zap_dvalue);
 | 
| +        if (TargetCPUFeatures::vfp_supported()) {
 | 
| +          double zap_dvalue = static_cast<double>(icount_);
 | 
| +          // Do not zap D0, as it may contain a float result.
 | 
| +          for (int i = D1; i <= D7; i++) {
 | 
| +            set_dregister(static_cast<DRegister>(i), zap_dvalue);
 | 
| +          }
 | 
| +          // The above loop also zaps overlapping registers S2-S15.
 | 
| +          // Registers D8-D15 (overlapping with S16-S31) are preserved.
 | 
| +#if defined(VFPv3_D32)
 | 
| +          for (int i = D16; i <= D31; i++) {
 | 
| +            set_dregister(static_cast<DRegister>(i), zap_dvalue);
 | 
| +          }
 | 
| +#endif
 | 
|          }
 | 
| -        // The above loop also zaps overlapping registers S2-S15.
 | 
| -        // Registers D8-D15 (overlapping with S16-S31) are preserved.
 | 
| -#ifdef VFPv3_D32
 | 
| -        for (int i = D16; i <= D31; i++) {
 | 
| -          set_dregister(static_cast<DRegister>(i), zap_dvalue);
 | 
| -        }
 | 
| -#endif  // VFPv3_D32
 | 
|  
 | 
|          // Return.
 | 
|          set_pc(saved_lr);
 | 
| @@ -1715,6 +1629,12 @@
 | 
|        }
 | 
|      } else if (instr->IsMultiplyOrSyncPrimitive()) {
 | 
|        if (instr->Bit(24) == 0) {
 | 
| +        if ((TargetCPUFeatures::arm_version() != ARMv7) &&
 | 
| +            (instr->Bits(21, 3) != 0)) {
 | 
| +          // mla ... smlal only supported on armv7.
 | 
| +          UnimplementedInstruction(instr);
 | 
| +          return;
 | 
| +        }
 | 
|          // multiply instructions.
 | 
|          Register rn = instr->RnField();
 | 
|          Register rd = instr->RdField();
 | 
| @@ -1820,49 +1740,25 @@
 | 
|            }
 | 
|          }
 | 
|        } else {
 | 
| -        // synchronization primitives
 | 
| -        Register rd = instr->RdField();
 | 
| -        Register rn = instr->RnField();
 | 
| -        uword addr = get_register(rn);
 | 
| -        switch (instr->Bits(20, 4)) {
 | 
| -          case 8: {
 | 
| -            // Format(instr, "strex'cond 'rd, 'rm, ['rn]");
 | 
| -            if (IsIllegalAddress(addr)) {
 | 
| -              HandleIllegalAccess(addr, instr);
 | 
| -            } else {
 | 
| -              Register rm = instr->RmField();
 | 
| -              set_register(rd, WriteExclusiveW(addr, get_register(rm), instr));
 | 
| -            }
 | 
| -            break;
 | 
| -          }
 | 
| -          case 9: {
 | 
| -            // Format(instr, "ldrex'cond 'rd, ['rn]");
 | 
| -            if (IsIllegalAddress(addr)) {
 | 
| -              HandleIllegalAccess(addr, instr);
 | 
| -            } else {
 | 
| -              set_register(rd, ReadExclusiveW(addr, instr));
 | 
| -            }
 | 
| -            break;
 | 
| -          }
 | 
| -          default: {
 | 
| -            UnimplementedInstruction(instr);
 | 
| -            break;
 | 
| -          }
 | 
| -        }
 | 
| +        UnimplementedInstruction(instr);
 | 
|        }
 | 
|      } else if (instr->Bit(25) == 1) {
 | 
|        // 16-bit immediate loads, msr (immediate), and hints
 | 
|        switch (instr->Bits(20, 5)) {
 | 
|          case 16:
 | 
|          case 20: {
 | 
| -          uint16_t imm16 = instr->MovwField();
 | 
| -          Register rd = instr->RdField();
 | 
| -          if (instr->Bit(22) == 0) {
 | 
| -            // Format(instr, "movw'cond 'rd, #'imm4_12");
 | 
| -            set_register(rd, imm16);
 | 
| +          if (TargetCPUFeatures::arm_version() == ARMv7) {
 | 
| +            uint16_t imm16 = instr->MovwField();
 | 
| +            Register rd = instr->RdField();
 | 
| +            if (instr->Bit(22) == 0) {
 | 
| +              // Format(instr, "movw'cond 'rd, #'imm4_12");
 | 
| +              set_register(rd, imm16);
 | 
| +            } else {
 | 
| +              // Format(instr, "movt'cond 'rd, #'imm4_12");
 | 
| +              set_register(rd, (get_register(rd) & 0xffff) | (imm16 << 16));
 | 
| +            }
 | 
|            } else {
 | 
| -            // Format(instr, "movt'cond 'rd, #'imm4_12");
 | 
| -            set_register(rd, (get_register(rd) & 0xffff) | (imm16 << 16));
 | 
| +            UnimplementedInstruction(instr);
 | 
|            }
 | 
|            break;
 | 
|          }
 | 
| @@ -2304,11 +2200,15 @@
 | 
|  
 | 
|  
 | 
|  void Simulator::DoDivision(Instr* instr) {
 | 
| -  ASSERT(TargetCPUFeatures::integer_division_supported());
 | 
| -  Register rd = instr->DivRdField();
 | 
| -  Register rn = instr->DivRnField();
 | 
| -  Register rm = instr->DivRmField();
 | 
| +  const Register rd = instr->DivRdField();
 | 
| +  const Register rn = instr->DivRnField();
 | 
| +  const Register rm = instr->DivRmField();
 | 
|  
 | 
| +  if (!TargetCPUFeatures::integer_division_supported()) {
 | 
| +    UnimplementedInstruction(instr);
 | 
| +    return;
 | 
| +  }
 | 
| +
 | 
|    // ARMv7-a does not trap on divide-by-zero. The destination register is just
 | 
|    // set to 0.
 | 
|    if (get_register(rm) == 0) {
 | 
| @@ -3539,7 +3439,7 @@
 | 
|    if (instr->ConditionField() == kSpecialCondition) {
 | 
|      if (instr->InstructionBits() == static_cast<int32_t>(0xf57ff01f)) {
 | 
|        // Format(instr, "clrex");
 | 
| -      ClearExclusive();
 | 
| +      UnimplementedInstruction(instr);
 | 
|      } else {
 | 
|        if (instr->IsSIMDDataProcessing()) {
 | 
|          DecodeSIMDDataProcessing(instr);
 | 
| @@ -3645,6 +3545,7 @@
 | 
|  
 | 
|    // Setup parameters.
 | 
|    if (fp_args) {
 | 
| +    ASSERT(TargetCPUFeatures::vfp_supported());
 | 
|      set_sregister(S0, bit_cast<float, int32_t>(parameter0));
 | 
|      set_sregister(S1, bit_cast<float, int32_t>(parameter1));
 | 
|      set_sregister(S2, bit_cast<float, int32_t>(parameter2));
 | 
| @@ -3683,15 +3584,26 @@
 | 
|    int32_t r10_val = get_register(R10);
 | 
|    int32_t r11_val = get_register(R11);
 | 
|  
 | 
| -  double d8_val = get_dregister(D8);
 | 
| -  double d9_val = get_dregister(D9);
 | 
| -  double d10_val = get_dregister(D10);
 | 
| -  double d11_val = get_dregister(D11);
 | 
| -  double d12_val = get_dregister(D12);
 | 
| -  double d13_val = get_dregister(D13);
 | 
| -  double d14_val = get_dregister(D14);
 | 
| -  double d15_val = get_dregister(D15);
 | 
| +  double d8_val = 0.0;
 | 
| +  double d9_val = 0.0;
 | 
| +  double d10_val = 0.0;
 | 
| +  double d11_val = 0.0;
 | 
| +  double d12_val = 0.0;
 | 
| +  double d13_val = 0.0;
 | 
| +  double d14_val = 0.0;
 | 
| +  double d15_val = 0.0;
 | 
|  
 | 
| +  if (TargetCPUFeatures::vfp_supported()) {
 | 
| +    d8_val = get_dregister(D8);
 | 
| +    d9_val = get_dregister(D9);
 | 
| +    d10_val = get_dregister(D10);
 | 
| +    d11_val = get_dregister(D11);
 | 
| +    d12_val = get_dregister(D12);
 | 
| +    d13_val = get_dregister(D13);
 | 
| +    d14_val = get_dregister(D14);
 | 
| +    d15_val = get_dregister(D15);
 | 
| +  }
 | 
| +
 | 
|    // Setup the callee-saved registers with a known value. To be able to check
 | 
|    // that they are preserved properly across dart execution.
 | 
|    int32_t callee_saved_value = icount_;
 | 
| @@ -3704,15 +3616,18 @@
 | 
|    set_register(R10, callee_saved_value);
 | 
|    set_register(R11, callee_saved_value);
 | 
|  
 | 
| -  double callee_saved_dvalue = static_cast<double>(icount_);
 | 
| -  set_dregister(D8, callee_saved_dvalue);
 | 
| -  set_dregister(D9, callee_saved_dvalue);
 | 
| -  set_dregister(D10, callee_saved_dvalue);
 | 
| -  set_dregister(D11, callee_saved_dvalue);
 | 
| -  set_dregister(D12, callee_saved_dvalue);
 | 
| -  set_dregister(D13, callee_saved_dvalue);
 | 
| -  set_dregister(D14, callee_saved_dvalue);
 | 
| -  set_dregister(D15, callee_saved_dvalue);
 | 
| +  double callee_saved_dvalue = 0.0;
 | 
| +  if (TargetCPUFeatures::vfp_supported()) {
 | 
| +    callee_saved_dvalue = static_cast<double>(icount_);
 | 
| +    set_dregister(D8, callee_saved_dvalue);
 | 
| +    set_dregister(D9, callee_saved_dvalue);
 | 
| +    set_dregister(D10, callee_saved_dvalue);
 | 
| +    set_dregister(D11, callee_saved_dvalue);
 | 
| +    set_dregister(D12, callee_saved_dvalue);
 | 
| +    set_dregister(D13, callee_saved_dvalue);
 | 
| +    set_dregister(D14, callee_saved_dvalue);
 | 
| +    set_dregister(D15, callee_saved_dvalue);
 | 
| +  }
 | 
|  
 | 
|    // Start the simulation
 | 
|    Execute();
 | 
| @@ -3727,14 +3642,16 @@
 | 
|    ASSERT(callee_saved_value == get_register(R10));
 | 
|    ASSERT(callee_saved_value == get_register(R11));
 | 
|  
 | 
| -  ASSERT(callee_saved_dvalue == get_dregister(D8));
 | 
| -  ASSERT(callee_saved_dvalue == get_dregister(D9));
 | 
| -  ASSERT(callee_saved_dvalue == get_dregister(D10));
 | 
| -  ASSERT(callee_saved_dvalue == get_dregister(D11));
 | 
| -  ASSERT(callee_saved_dvalue == get_dregister(D12));
 | 
| -  ASSERT(callee_saved_dvalue == get_dregister(D13));
 | 
| -  ASSERT(callee_saved_dvalue == get_dregister(D14));
 | 
| -  ASSERT(callee_saved_dvalue == get_dregister(D15));
 | 
| +  if (TargetCPUFeatures::vfp_supported()) {
 | 
| +    ASSERT(callee_saved_dvalue == get_dregister(D8));
 | 
| +    ASSERT(callee_saved_dvalue == get_dregister(D9));
 | 
| +    ASSERT(callee_saved_dvalue == get_dregister(D10));
 | 
| +    ASSERT(callee_saved_dvalue == get_dregister(D11));
 | 
| +    ASSERT(callee_saved_dvalue == get_dregister(D12));
 | 
| +    ASSERT(callee_saved_dvalue == get_dregister(D13));
 | 
| +    ASSERT(callee_saved_dvalue == get_dregister(D14));
 | 
| +    ASSERT(callee_saved_dvalue == get_dregister(D15));
 | 
| +  }
 | 
|  
 | 
|    // Restore callee-saved registers with the original value.
 | 
|    set_register(R4, r4_val);
 | 
| @@ -3746,19 +3663,22 @@
 | 
|    set_register(R10, r10_val);
 | 
|    set_register(R11, r11_val);
 | 
|  
 | 
| -  set_dregister(D8, d8_val);
 | 
| -  set_dregister(D9, d9_val);
 | 
| -  set_dregister(D10, d10_val);
 | 
| -  set_dregister(D11, d11_val);
 | 
| -  set_dregister(D12, d12_val);
 | 
| -  set_dregister(D13, d13_val);
 | 
| -  set_dregister(D14, d14_val);
 | 
| -  set_dregister(D15, d15_val);
 | 
| +  if (TargetCPUFeatures::vfp_supported()) {
 | 
| +    set_dregister(D8, d8_val);
 | 
| +    set_dregister(D9, d9_val);
 | 
| +    set_dregister(D10, d10_val);
 | 
| +    set_dregister(D11, d11_val);
 | 
| +    set_dregister(D12, d12_val);
 | 
| +    set_dregister(D13, d13_val);
 | 
| +    set_dregister(D14, d14_val);
 | 
| +    set_dregister(D15, d15_val);
 | 
| +  }
 | 
|  
 | 
|    // Restore the SP register and return R1:R0.
 | 
|    set_register(SP, sp_before_call);
 | 
|    int64_t return_value;
 | 
|    if (fp_return) {
 | 
| +    ASSERT(TargetCPUFeatures::vfp_supported());
 | 
|      return_value = bit_cast<int64_t, double>(get_dregister(D0));
 | 
|    } else {
 | 
|      return_value = Utils::LowHighTo64Bits(get_register(R0), get_register(R1));
 | 
| 
 |