| Index: runtime/vm/intermediate_language_arm.cc
 | 
| diff --git a/runtime/vm/intermediate_language_arm.cc b/runtime/vm/intermediate_language_arm.cc
 | 
| index 073e59d46df7c6bb3ce0aa2ae5906dba77f83c77..14ab139fba4a7f315d63e62f09f893afbea99771 100644
 | 
| --- a/runtime/vm/intermediate_language_arm.cc
 | 
| +++ b/runtime/vm/intermediate_language_arm.cc
 | 
| @@ -305,14 +305,24 @@ LocationSummary* UnboxedConstantInstr::MakeLocationSummary(Isolate* isolate,
 | 
|  void UnboxedConstantInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
 | 
|    // The register allocator drops constant definitions that have no uses.
 | 
|    if (!locs()->out(0).IsInvalid()) {
 | 
| -    if (Utils::DoublesBitEqual(Double::Cast(value()).value(), 0.0) &&
 | 
| -        TargetCPUFeatures::neon_supported()) {
 | 
| -      const QRegister dst = locs()->out(0).fpu_reg();
 | 
| -      __ veorq(dst, dst, dst);
 | 
| -    } else {
 | 
| -      const DRegister dst = EvenDRegisterOf(locs()->out(0).fpu_reg());
 | 
| -      const Register temp = locs()->temp(0).reg();
 | 
| -      __ LoadDImmediate(dst, Double::Cast(value()).value(), temp);
 | 
| +    switch (representation_) {
 | 
| +      case kUnboxedDouble:
 | 
| +        if (Utils::DoublesBitEqual(Double::Cast(value()).value(), 0.0) &&
 | 
| +            TargetCPUFeatures::neon_supported()) {
 | 
| +          const QRegister dst = locs()->out(0).fpu_reg();
 | 
| +          __ veorq(dst, dst, dst);
 | 
| +        } else {
 | 
| +          const DRegister dst = EvenDRegisterOf(locs()->out(0).fpu_reg());
 | 
| +          const Register temp = locs()->temp(0).reg();
 | 
| +          __ LoadDImmediate(dst, Double::Cast(value()).value(), temp);
 | 
| +        }
 | 
| +        break;
 | 
| +      case kUnboxedInt32:
 | 
| +        __ LoadImmediate(locs()->out(0).reg(), Smi::Cast(value()).Value());
 | 
| +        break;
 | 
| +      default:
 | 
| +        UNREACHABLE();
 | 
| +        break;
 | 
|      }
 | 
|    }
 | 
|  }
 | 
| @@ -1186,7 +1196,7 @@ LocationSummary* LoadIndexedInstr::MakeLocationSummary(Isolate* isolate,
 | 
|                            true,  // Load.
 | 
|                            &needs_base)) {
 | 
|      // CanBeImmediateIndex must return false for unsafe smis.
 | 
| -    locs->set_in(1, Location::Constant(index()->BoundConstant()));
 | 
| +    locs->set_in(1, Location::Constant(index()->definition()->AsConstant()));
 | 
|    } else {
 | 
|      locs->set_in(1, Location::RequiresRegister());
 | 
|    }
 | 
| @@ -1387,7 +1397,7 @@ LocationSummary* StoreIndexedInstr::MakeLocationSummary(Isolate* isolate,
 | 
|          isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall);
 | 
|  
 | 
|      // CanBeImmediateIndex must return false for unsafe smis.
 | 
| -    locs->set_in(1, Location::Constant(index()->BoundConstant()));
 | 
| +    locs->set_in(1, Location::Constant(index()->definition()->AsConstant()));
 | 
|      if (needs_base) {
 | 
|        locs->set_temp(0, Location::RequiresRegister());
 | 
|      }
 | 
| @@ -2960,7 +2970,7 @@ LocationSummary* BinarySmiOpInstr::MakeLocationSummary(Isolate* isolate,
 | 
|      summary->set_in(0, Location::RequiresRegister());
 | 
|      if (RightIsPowerOfTwoConstant()) {
 | 
|        ConstantInstr* right_constant = right()->definition()->AsConstant();
 | 
| -      summary->set_in(1, Location::Constant(right_constant->value()));
 | 
| +      summary->set_in(1, Location::Constant(right_constant));
 | 
|        summary->set_temp(0, Location::RequiresRegister());
 | 
|      } else {
 | 
|        summary->set_in(1, Location::RequiresRegister());
 | 
| @@ -3066,6 +3076,8 @@ void BinarySmiOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
 | 
|                __ CheckMultSignedOverflow(left, IP, result, dtmp0, dtmp1, deopt);
 | 
|                __ mul(result, left, IP);
 | 
|              } else {
 | 
| +             // TODO(vegorov): never emit this instruction if hardware does not
 | 
| +             // support it! This will lead to deopt cycle penalizing the code.
 | 
|                __ b(deopt);
 | 
|              }
 | 
|            }
 | 
| @@ -3206,6 +3218,8 @@ void BinarySmiOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
 | 
|            __ CheckMultSignedOverflow(IP, right, result, dtmp0, dtmp1, deopt);
 | 
|            __ mul(result, IP, right);
 | 
|          } else {
 | 
| +          // TODO(vegorov): never emit this instruction if hardware does not
 | 
| +          // support it! This will lead to deopt cycle penalizing the code.
 | 
|            __ b(deopt);
 | 
|          }
 | 
|        }
 | 
| @@ -3239,6 +3253,8 @@ void BinarySmiOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
 | 
|          __ SmiUntag(IP, right);
 | 
|          __ IntegerDivide(result, temp, IP, dtemp, DTMP);
 | 
|        } else {
 | 
| +        // TODO(vegorov): never emit this instruction if hardware does not
 | 
| +        // support it! This will lead to deopt cycle penalizing the code.
 | 
|          __ b(deopt);
 | 
|        }
 | 
|  
 | 
| @@ -3262,6 +3278,8 @@ void BinarySmiOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
 | 
|          __ SmiUntag(IP, right);
 | 
|          __ IntegerDivide(result, temp, IP, dtemp, DTMP);
 | 
|        } else {
 | 
| +        // TODO(vegorov): never emit this instruction if hardware does not
 | 
| +        // support it! This will lead to deopt cycle penalizing the code.
 | 
|          __ b(deopt);
 | 
|        }
 | 
|        __ SmiUntag(IP, right);
 | 
| @@ -3324,6 +3342,280 @@ void BinarySmiOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
 | 
|  }
 | 
|  
 | 
|  
 | 
| +static void EmitInt32ShiftLeft(FlowGraphCompiler* compiler,
 | 
| +                               BinaryInt32OpInstr* shift_left) {
 | 
| +  const bool is_truncating = shift_left->IsTruncating();
 | 
| +  const LocationSummary& locs = *shift_left->locs();
 | 
| +  const Register left = locs.in(0).reg();
 | 
| +  const Register result = locs.out(0).reg();
 | 
| +  Label* deopt = shift_left->CanDeoptimize() ?
 | 
| +      compiler->AddDeoptStub(shift_left->deopt_id(), ICData::kDeoptBinarySmiOp)
 | 
| +      : NULL;
 | 
| +  ASSERT(locs.in(1).IsConstant());
 | 
| +  const Object& constant = locs.in(1).constant();
 | 
| +  ASSERT(constant.IsSmi());
 | 
| +  // Immediate shift operation takes 5 bits for the count.
 | 
| +  const intptr_t kCountLimit = 0x1F;
 | 
| +  const intptr_t value = Smi::Cast(constant).Value();
 | 
| +  if (value == 0) {
 | 
| +    __ MoveRegister(result, left);
 | 
| +  } else if ((value < 0) || (value >= kCountLimit)) {
 | 
| +    // This condition may not be known earlier in some cases because
 | 
| +    // of constant propagation, inlining, etc.
 | 
| +    if ((value >= kCountLimit) && is_truncating) {
 | 
| +      __ mov(result, Operand(0));
 | 
| +    } else {
 | 
| +      // Result is Mint or exception.
 | 
| +      __ b(deopt);
 | 
| +    }
 | 
| +  } else {
 | 
| +    if (!is_truncating) {
 | 
| +      // Check for overflow (preserve left).
 | 
| +      __ Lsl(IP, left, value);
 | 
| +      __ cmp(left, Operand(IP, ASR, value));
 | 
| +      __ b(deopt, NE);  // Overflow.
 | 
| +    }
 | 
| +    // Shift for result now we know there is no overflow.
 | 
| +    __ Lsl(result, left, value);
 | 
| +  }
 | 
| +}
 | 
| +
 | 
| +
 | 
| +LocationSummary* BinaryInt32OpInstr::MakeLocationSummary(Isolate* isolate,
 | 
| +                                                         bool opt) const {
 | 
| +  const intptr_t kNumInputs = 2;
 | 
| +  // Calculate number of temporaries.
 | 
| +  intptr_t num_temps = 0;
 | 
| +  if (((op_kind() == Token::kSHL) && !IsTruncating()) ||
 | 
| +      (op_kind() == Token::kSHR)) {
 | 
| +    num_temps = 1;
 | 
| +  } else if ((op_kind() == Token::kMUL) &&
 | 
| +             (TargetCPUFeatures::arm_version() != ARMv7)) {
 | 
| +    num_temps = 1;
 | 
| +  }
 | 
| +  LocationSummary* summary = new(isolate) LocationSummary(
 | 
| +      isolate, kNumInputs, num_temps, LocationSummary::kNoCall);
 | 
| +  summary->set_in(0, Location::RequiresRegister());
 | 
| +  summary->set_in(1, Location::RegisterOrSmiConstant(right()));
 | 
| +  if (((op_kind() == Token::kSHL) && !IsTruncating()) ||
 | 
| +      (op_kind() == Token::kSHR)) {
 | 
| +    summary->set_temp(0, Location::RequiresRegister());
 | 
| +  }
 | 
| +  if (op_kind() == Token::kMUL) {
 | 
| +    if (TargetCPUFeatures::arm_version() != ARMv7) {
 | 
| +      summary->set_temp(0, Location::RequiresFpuRegister());
 | 
| +    }
 | 
| +  }
 | 
| +  // We make use of 3-operand instructions by not requiring result register
 | 
| +  // to be identical to first input register as on Intel.
 | 
| +  summary->set_out(0, Location::RequiresRegister());
 | 
| +  return summary;
 | 
| +}
 | 
| +
 | 
| +
 | 
| +void BinaryInt32OpInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
 | 
| +  if (op_kind() == Token::kSHL) {
 | 
| +    EmitInt32ShiftLeft(compiler, this);
 | 
| +    return;
 | 
| +  }
 | 
| +
 | 
| +  const Register left = locs()->in(0).reg();
 | 
| +  const Register result = locs()->out(0).reg();
 | 
| +  Label* deopt = NULL;
 | 
| +  if (CanDeoptimize()) {
 | 
| +    deopt = compiler->AddDeoptStub(deopt_id(), ICData::kDeoptBinarySmiOp);
 | 
| +  }
 | 
| +
 | 
| +  if (locs()->in(1).IsConstant()) {
 | 
| +    const Object& constant = locs()->in(1).constant();
 | 
| +    ASSERT(constant.IsSmi());
 | 
| +    const int32_t value = Smi::Cast(constant).Value();
 | 
| +    switch (op_kind()) {
 | 
| +      case Token::kADD: {
 | 
| +        if (deopt == NULL) {
 | 
| +          __ AddImmediate(result, left, value);
 | 
| +        } else {
 | 
| +          __ AddImmediateSetFlags(result, left, value);
 | 
| +          __ b(deopt, VS);
 | 
| +        }
 | 
| +        break;
 | 
| +      }
 | 
| +      case Token::kSUB: {
 | 
| +        if (deopt == NULL) {
 | 
| +          __ AddImmediate(result, left, -value);
 | 
| +        } else {
 | 
| +          // Negating value and using AddImmediateSetFlags would not detect the
 | 
| +          // overflow when value == kMinInt32.
 | 
| +          __ SubImmediateSetFlags(result, left, value);
 | 
| +          __ b(deopt, VS);
 | 
| +        }
 | 
| +        break;
 | 
| +      }
 | 
| +      case Token::kMUL: {
 | 
| +        if (deopt == NULL) {
 | 
| +          if (value == 2) {
 | 
| +            __ mov(result, Operand(left, LSL, 1));
 | 
| +          } else {
 | 
| +            __ LoadImmediate(IP, value);
 | 
| +            __ mul(result, left, IP);
 | 
| +          }
 | 
| +        } else {
 | 
| +          if (value == 2) {
 | 
| +            __ CompareImmediate(left, 0xC0000000);
 | 
| +            __ b(deopt, MI);
 | 
| +            __ mov(result, Operand(left, LSL, 1));
 | 
| +          } else {
 | 
| +            if (TargetCPUFeatures::arm_version() == ARMv7) {
 | 
| +              __ LoadImmediate(IP, value);
 | 
| +              __ smull(result, IP, left, IP);
 | 
| +              // IP: result bits 32..63.
 | 
| +              __ cmp(IP, Operand(result, ASR, 31));
 | 
| +              __ b(deopt, NE);
 | 
| +            } else if (TargetCPUFeatures::can_divide()) {
 | 
| +              const QRegister qtmp = locs()->temp(0).fpu_reg();
 | 
| +              const DRegister dtmp0 = EvenDRegisterOf(qtmp);
 | 
| +              const DRegister dtmp1 = OddDRegisterOf(qtmp);
 | 
| +              __ LoadImmediate(IP, value);
 | 
| +              __ CheckMultSignedOverflow(left, IP, result, dtmp0, dtmp1, deopt);
 | 
| +              __ mul(result, left, IP);
 | 
| +            } else {
 | 
| +              // TODO(vegorov): never emit this instruction if hardware does not
 | 
| +              // support it! This will lead to deopt cycle penalizing the code.
 | 
| +              __ b(deopt);
 | 
| +            }
 | 
| +          }
 | 
| +        }
 | 
| +        break;
 | 
| +      }
 | 
| +      case Token::kBIT_AND: {
 | 
| +        // No overflow check.
 | 
| +        Operand o;
 | 
| +        if (Operand::CanHold(value, &o)) {
 | 
| +          __ and_(result, left, o);
 | 
| +        } else if (Operand::CanHold(~value, &o)) {
 | 
| +          __ bic(result, left, o);
 | 
| +        } else {
 | 
| +          __ LoadImmediate(IP, value);
 | 
| +          __ and_(result, left, Operand(IP));
 | 
| +        }
 | 
| +        break;
 | 
| +      }
 | 
| +      case Token::kBIT_OR: {
 | 
| +        // No overflow check.
 | 
| +        Operand o;
 | 
| +        if (Operand::CanHold(value, &o)) {
 | 
| +          __ orr(result, left, o);
 | 
| +        } else {
 | 
| +          __ LoadImmediate(IP, value);
 | 
| +          __ orr(result, left, Operand(IP));
 | 
| +        }
 | 
| +        break;
 | 
| +      }
 | 
| +      case Token::kBIT_XOR: {
 | 
| +        // No overflow check.
 | 
| +        Operand o;
 | 
| +        if (Operand::CanHold(value, &o)) {
 | 
| +          __ eor(result, left, o);
 | 
| +        } else {
 | 
| +          __ LoadImmediate(IP, value);
 | 
| +          __ eor(result, left, Operand(IP));
 | 
| +        }
 | 
| +        break;
 | 
| +      }
 | 
| +      case Token::kSHR: {
 | 
| +        // sarl operation masks the count to 5 bits.
 | 
| +        const intptr_t kCountLimit = 0x1F;
 | 
| +
 | 
| +        if (value == 0) {
 | 
| +          // TODO(vegorov): should be handled outside.
 | 
| +          __ MoveRegister(result, left);
 | 
| +          break;
 | 
| +        } else if (value < 0) {
 | 
| +          // TODO(vegorov): should be handled outside.
 | 
| +          __ b(deopt);
 | 
| +          break;
 | 
| +        }
 | 
| +
 | 
| +        if (value >= kCountLimit) {
 | 
| +          __ Asr(result, left, kCountLimit);
 | 
| +        } else {
 | 
| +          __ Asr(result, left, value);
 | 
| +        }
 | 
| +        break;
 | 
| +      }
 | 
| +
 | 
| +      default:
 | 
| +        UNREACHABLE();
 | 
| +        break;
 | 
| +    }
 | 
| +    return;
 | 
| +  }
 | 
| +
 | 
| +  const Register right = locs()->in(1).reg();
 | 
| +  switch (op_kind()) {
 | 
| +    case Token::kADD: {
 | 
| +      if (deopt == NULL) {
 | 
| +        __ add(result, left, Operand(right));
 | 
| +      } else {
 | 
| +        __ adds(result, left, Operand(right));
 | 
| +        __ b(deopt, VS);
 | 
| +      }
 | 
| +      break;
 | 
| +    }
 | 
| +    case Token::kSUB: {
 | 
| +      if (deopt == NULL) {
 | 
| +        __ sub(result, left, Operand(right));
 | 
| +      } else {
 | 
| +        __ subs(result, left, Operand(right));
 | 
| +        __ b(deopt, VS);
 | 
| +      }
 | 
| +      break;
 | 
| +    }
 | 
| +    case Token::kMUL: {
 | 
| +      if (deopt == NULL) {
 | 
| +        __ mul(result, left, right);
 | 
| +      } else {
 | 
| +        if (TargetCPUFeatures::arm_version() == ARMv7) {
 | 
| +          __ smull(result, IP, left, right);
 | 
| +          // IP: result bits 32..63.
 | 
| +          __ cmp(IP, Operand(result, ASR, 31));
 | 
| +          __ b(deopt, NE);
 | 
| +        } else if (TargetCPUFeatures::can_divide()) {
 | 
| +          const QRegister qtmp = locs()->temp(0).fpu_reg();
 | 
| +          const DRegister dtmp0 = EvenDRegisterOf(qtmp);
 | 
| +          const DRegister dtmp1 = OddDRegisterOf(qtmp);
 | 
| +          __ CheckMultSignedOverflow(left, right, result, dtmp0, dtmp1, deopt);
 | 
| +          __ mul(result, left, right);
 | 
| +        } else {
 | 
| +          // TODO(vegorov): never emit this instruction if hardware does not
 | 
| +          // support it! This will lead to deopt cycle penalizing the code.
 | 
| +          __ b(deopt);
 | 
| +        }
 | 
| +      }
 | 
| +      break;
 | 
| +    }
 | 
| +    case Token::kBIT_AND: {
 | 
| +      // No overflow check.
 | 
| +      __ and_(result, left, Operand(right));
 | 
| +      break;
 | 
| +    }
 | 
| +    case Token::kBIT_OR: {
 | 
| +      // No overflow check.
 | 
| +      __ orr(result, left, Operand(right));
 | 
| +      break;
 | 
| +    }
 | 
| +    case Token::kBIT_XOR: {
 | 
| +      // No overflow check.
 | 
| +      __ eor(result, left, Operand(right));
 | 
| +      break;
 | 
| +    }
 | 
| +    default:
 | 
| +      UNREACHABLE();
 | 
| +      break;
 | 
| +  }
 | 
| +}
 | 
| +
 | 
| +
 | 
|  LocationSummary* CheckEitherNonSmiInstr::MakeLocationSummary(Isolate* isolate,
 | 
|                                                               bool opt) const {
 | 
|    intptr_t left_cid = left()->Type()->ToCid();
 | 
| @@ -5039,6 +5331,26 @@ void UnaryDoubleOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
 | 
|  }
 | 
|  
 | 
|  
 | 
| +LocationSummary* Int32ToDoubleInstr::MakeLocationSummary(Isolate* isolate,
 | 
| +                                                         bool opt) const {
 | 
| +  const intptr_t kNumInputs = 1;
 | 
| +  const intptr_t kNumTemps = 0;
 | 
| +  LocationSummary* result = new(isolate) LocationSummary(
 | 
| +      isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall);
 | 
| +  result->set_in(0, Location::RequiresRegister());
 | 
| +  result->set_out(0, Location::RequiresFpuRegister());
 | 
| +  return result;
 | 
| +}
 | 
| +
 | 
| +
 | 
| +void Int32ToDoubleInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
 | 
| +  const Register value = locs()->in(0).reg();
 | 
| +  const DRegister result = EvenDRegisterOf(locs()->out(0).fpu_reg());
 | 
| +  __ vmovsr(STMP, value);
 | 
| +  __ vcvtdi(result, STMP);
 | 
| +}
 | 
| +
 | 
| +
 | 
|  LocationSummary* SmiToDoubleInstr::MakeLocationSummary(Isolate* isolate,
 | 
|                                                         bool opt) const {
 | 
|    const intptr_t kNumInputs = 1;
 | 
| @@ -5482,6 +5794,8 @@ void MergedMathInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
 | 
|        __ SmiUntag(IP, right);
 | 
|        __ IntegerDivide(result_div, temp, IP, dtemp, DTMP);
 | 
|      } else {
 | 
| +      // TODO(vegorov): never emit this instruction if hardware does not
 | 
| +      // support it! This will lead to deopt cycle penalizing the code.
 | 
|        __ b(deopt);
 | 
|      }
 | 
|  
 | 
| @@ -6001,6 +6315,8 @@ void BinaryMintOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
 | 
|          __ b(deopt, NE);
 | 
|          __ smull(out_lo, out_hi, left_lo, right_lo);
 | 
|        } else {
 | 
| +        // TODO(vegorov): never emit this instruction if hardware does not
 | 
| +        // support it! This will lead to deopt cycle penalizing the code.
 | 
|          __ b(deopt);
 | 
|        }
 | 
|        break;
 | 
| @@ -6218,16 +6534,6 @@ CompileType UnaryUint32OpInstr::ComputeType() const {
 | 
|  }
 | 
|  
 | 
|  
 | 
| -CompileType BoxUint32Instr::ComputeType() const {
 | 
| -  return CompileType::Int();
 | 
| -}
 | 
| -
 | 
| -
 | 
| -CompileType UnboxUint32Instr::ComputeType() const {
 | 
| -  return CompileType::Int();
 | 
| -}
 | 
| -
 | 
| -
 | 
|  LocationSummary* BinaryUint32OpInstr::MakeLocationSummary(Isolate* isolate,
 | 
|                                                            bool opt) const {
 | 
|    const intptr_t kNumInputs = 2;
 | 
| @@ -6480,6 +6786,134 @@ void UnboxUint32Instr::EmitNativeCode(FlowGraphCompiler* compiler) {
 | 
|  }
 | 
|  
 | 
|  
 | 
| +LocationSummary* BoxInt32Instr::MakeLocationSummary(Isolate* isolate,
 | 
| +                                                     bool opt) const {
 | 
| +  const intptr_t kNumInputs = 1;
 | 
| +  const intptr_t kNumTemps = ValueFitsSmi() ? 0 : 1;
 | 
| +  LocationSummary* summary = new(isolate) LocationSummary(
 | 
| +      isolate,
 | 
| +      kNumInputs,
 | 
| +      kNumTemps,
 | 
| +      ValueFitsSmi() ? LocationSummary::kNoCall
 | 
| +                     : LocationSummary::kCallOnSlowPath);
 | 
| +  summary->set_in(0, Location::RequiresRegister());
 | 
| +  if (!ValueFitsSmi()) {
 | 
| +    summary->set_temp(0, Location::RequiresRegister());
 | 
| +  }
 | 
| +  summary->set_out(0, Location::RequiresRegister());
 | 
| +  return summary;
 | 
| +}
 | 
| +
 | 
| +
 | 
| +void BoxInt32Instr::EmitNativeCode(FlowGraphCompiler* compiler) {
 | 
| +  Register value = locs()->in(0).reg();
 | 
| +  Register out = locs()->out(0).reg();
 | 
| +  ASSERT(value != out);
 | 
| +
 | 
| +  __ Lsl(out, value, 1);
 | 
| +  if (!ValueFitsSmi()) {
 | 
| +    Register temp = locs()->temp(0).reg();
 | 
| +    Label done;
 | 
| +    __ cmp(value, Operand(out, ASR, 1));
 | 
| +    __ b(&done, EQ);
 | 
| +    BoxAllocationSlowPath::Allocate(
 | 
| +        compiler,
 | 
| +        this,
 | 
| +        compiler->mint_class(),
 | 
| +        out,
 | 
| +        temp);
 | 
| +    __ Asr(temp, value, kBitsPerWord - 1);
 | 
| +    __ StoreToOffset(kWord,
 | 
| +                     value,
 | 
| +                     out,
 | 
| +                     Mint::value_offset() - kHeapObjectTag);
 | 
| +    __ StoreToOffset(kWord,
 | 
| +                     temp,
 | 
| +                     out,
 | 
| +                     Mint::value_offset() - kHeapObjectTag + kWordSize);
 | 
| +    __ Bind(&done);
 | 
| +  }
 | 
| +}
 | 
| +
 | 
| +
 | 
| +
 | 
| +LocationSummary* UnboxInt32Instr::MakeLocationSummary(Isolate* isolate,
 | 
| +                                                      bool opt) const {
 | 
| +  const intptr_t value_cid = value()->Type()->ToCid();
 | 
| +  const intptr_t kNumInputs = 1;
 | 
| +  const intptr_t kNumTemps =
 | 
| +      ((value_cid == kMintCid) || (value_cid == kSmiCid)) ? 0 : 1;
 | 
| +  LocationSummary* summary = new(isolate) LocationSummary(
 | 
| +      isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall);
 | 
| +  summary->set_in(0, Location::RequiresRegister());
 | 
| +  if (kNumTemps > 0) {
 | 
| +    summary->set_temp(0, Location::RequiresRegister());
 | 
| +  }
 | 
| +  summary->set_out(0, Location::RequiresRegister());
 | 
| +  return summary;
 | 
| +}
 | 
| +
 | 
| +
 | 
| +static void LoadInt32FromMint(FlowGraphCompiler* compiler,
 | 
| +                              Register mint,
 | 
| +                              Register result,
 | 
| +                              Register temp,
 | 
| +                              Label* deopt) {
 | 
| +  __ LoadFromOffset(kWord,
 | 
| +                    result,
 | 
| +                    mint,
 | 
| +                    Mint::value_offset() - kHeapObjectTag);
 | 
| +  if (deopt != NULL) {
 | 
| +    __ LoadFromOffset(kWord,
 | 
| +                      temp,
 | 
| +                      mint,
 | 
| +                      Mint::value_offset() - kHeapObjectTag + kWordSize);
 | 
| +    __ cmp(temp, Operand(result, ASR, kBitsPerWord - 1));
 | 
| +    __ b(deopt, NE);
 | 
| +  }
 | 
| +}
 | 
| +
 | 
| +
 | 
| +void UnboxInt32Instr::EmitNativeCode(FlowGraphCompiler* compiler) {
 | 
| +  const intptr_t value_cid = value()->Type()->ToCid();
 | 
| +  const Register value = locs()->in(0).reg();
 | 
| +  const Register out = locs()->out(0).reg();
 | 
| +  ASSERT(value != out);
 | 
| +
 | 
| +  if (value_cid == kMintCid) {
 | 
| +    Register temp = CanDeoptimize() ? locs()->temp(0).reg() : kNoRegister;
 | 
| +    Label* deopt = CanDeoptimize() ?
 | 
| +        compiler->AddDeoptStub(deopt_id_, ICData::kDeoptUnboxInteger) : NULL;
 | 
| +    LoadInt32FromMint(compiler,
 | 
| +                      value,
 | 
| +                      out,
 | 
| +                      temp,
 | 
| +                      deopt);
 | 
| +  } else if (value_cid == kSmiCid) {
 | 
| +    __ SmiUntag(out, value);
 | 
| +  } else {
 | 
| +    Register temp = locs()->temp(0).reg();
 | 
| +    Label* deopt = compiler->AddDeoptStub(deopt_id_,
 | 
| +                                          ICData::kDeoptUnboxInteger);
 | 
| +    Label done;
 | 
| +    __ tst(value, Operand(kSmiTagMask));
 | 
| +    // Smi case.
 | 
| +    __ mov(out, Operand(value), EQ);
 | 
| +    __ SmiUntag(out, EQ);
 | 
| +    __ b(&done, EQ);
 | 
| +    // Mint case.
 | 
| +    __ CompareClassId(value, kMintCid, temp);
 | 
| +    __ b(deopt, NE);
 | 
| +    LoadInt32FromMint(compiler,
 | 
| +                      value,
 | 
| +                      out,
 | 
| +                      temp,
 | 
| +                      deopt);
 | 
| +    __ Bind(&done);
 | 
| +  }
 | 
| +}
 | 
| +
 | 
| +
 | 
|  LocationSummary* UnboxedIntConverterInstr::MakeLocationSummary(Isolate* isolate,
 | 
|                                                                 bool opt) const {
 | 
|    const intptr_t kNumInputs = 1;
 | 
| @@ -6487,36 +6921,71 @@ LocationSummary* UnboxedIntConverterInstr::MakeLocationSummary(Isolate* isolate,
 | 
|    LocationSummary* summary = new(isolate) LocationSummary(
 | 
|        isolate, kNumInputs, kNumTemps, LocationSummary::kNoCall);
 | 
|    if (from() == kUnboxedMint) {
 | 
| +    ASSERT((to() == kUnboxedUint32) || (to() == kUnboxedInt32));
 | 
|      summary->set_in(0, Location::Pair(Location::RequiresRegister(),
 | 
|                                        Location::RequiresRegister()));
 | 
|      summary->set_out(0, Location::RequiresRegister());
 | 
| -  } else {
 | 
| -    ASSERT(from() == kUnboxedUint32);
 | 
| +  } else if (to() == kUnboxedMint) {
 | 
| +    ASSERT((from() == kUnboxedUint32) || (from() == kUnboxedInt32));
 | 
|      summary->set_in(0, Location::RequiresRegister());
 | 
|      summary->set_out(0, Location::Pair(Location::RequiresRegister(),
 | 
|                                         Location::RequiresRegister()));
 | 
| +  } else {
 | 
| +    ASSERT((to() == kUnboxedUint32) || (to() == kUnboxedInt32));
 | 
| +    ASSERT((from() == kUnboxedUint32) || (from() == kUnboxedInt32));
 | 
| +    summary->set_in(0, Location::RequiresRegister());
 | 
| +    summary->set_out(0, Location::SameAsFirstInput());
 | 
|    }
 | 
|    return summary;
 | 
|  }
 | 
|  
 | 
|  
 | 
|  void UnboxedIntConverterInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
 | 
| -  if (from() == kUnboxedMint) {
 | 
| +  if (from() == kUnboxedInt32 && to() == kUnboxedUint32) {
 | 
| +    const Register out = locs()->out(0).reg();
 | 
| +    // Representations are bitwise equivalent.
 | 
| +    ASSERT(out == locs()->in(0).reg());
 | 
| +  } else if (from() == kUnboxedUint32 && to() == kUnboxedInt32) {
 | 
| +    const Register out = locs()->out(0).reg();
 | 
| +    // Representations are bitwise equivalent.
 | 
| +    ASSERT(out == locs()->in(0).reg());
 | 
| +    if (CanDeoptimize()) {
 | 
| +      Label* deopt =
 | 
| +          compiler->AddDeoptStub(deopt_id(), ICData::kDeoptUnboxInteger);
 | 
| +      __ tst(out, Operand(out));
 | 
| +      __ b(deopt, MI);
 | 
| +    }
 | 
| +  } else if (from() == kUnboxedMint) {
 | 
| +    ASSERT(to() == kUnboxedUint32 || to() == kUnboxedInt32);
 | 
|      PairLocation* in_pair = locs()->in(0).AsPairLocation();
 | 
|      Register in_lo = in_pair->At(0).reg();
 | 
| +    Register in_hi = in_pair->At(1).reg();
 | 
|      Register out = locs()->out(0).reg();
 | 
|      // Copy low word.
 | 
|      __ mov(out, Operand(in_lo));
 | 
| -  } else {
 | 
| -    ASSERT(from() == kUnboxedUint32);
 | 
| +    if (CanDeoptimize()) {
 | 
| +      Label* deopt =
 | 
| +          compiler->AddDeoptStub(deopt_id(), ICData::kDeoptUnboxInteger);
 | 
| +      ASSERT(to() == kUnboxedInt32);
 | 
| +      __ cmp(in_hi, Operand(in_lo, ASR, kBitsPerWord - 1));
 | 
| +      __ b(deopt, NE);
 | 
| +    }
 | 
| +  } else if (from() == kUnboxedUint32 || from() == kUnboxedInt32) {
 | 
| +    ASSERT(to() == kUnboxedMint);
 | 
|      Register in = locs()->in(0).reg();
 | 
|      PairLocation* out_pair = locs()->out(0).AsPairLocation();
 | 
|      Register out_lo = out_pair->At(0).reg();
 | 
|      Register out_hi = out_pair->At(1).reg();
 | 
|      // Copy low word.
 | 
|      __ mov(out_lo, Operand(in));
 | 
| -    // Zero upper word.
 | 
| -    __ eor(out_hi, out_hi, Operand(out_hi));
 | 
| +    if (from() == kUnboxedUint32) {
 | 
| +      __ eor(out_hi, out_hi, Operand(out_hi));
 | 
| +    } else {
 | 
| +      ASSERT(from() == kUnboxedInt32);
 | 
| +      __ mov(out_hi, Operand(in, ASR, kBitsPerWord - 1));
 | 
| +    }
 | 
| +  } else {
 | 
| +    UNREACHABLE();
 | 
|    }
 | 
|  }
 | 
|  
 | 
| 
 |