| Index: src/a64/lithium-codegen-a64.cc
|
| diff --git a/src/a64/lithium-codegen-a64.cc b/src/a64/lithium-codegen-a64.cc
|
| index b358742b52e762158f887ee2e4b58d5509deb958..0bb420cf590a83f799d0225af6866643f9aa32ab 100644
|
| --- a/src/a64/lithium-codegen-a64.cc
|
| +++ b/src/a64/lithium-codegen-a64.cc
|
| @@ -342,10 +342,6 @@ void LCodeGen::AddToTranslation(LEnvironment* environment,
|
| }
|
| } else if (op->IsDoubleStackSlot()) {
|
| translation->StoreDoubleStackSlot(op->index());
|
| - } else if (op->IsArgument()) {
|
| - ASSERT(is_tagged);
|
| - int src_index = GetStackSlotCount() + op->index();
|
| - translation->StoreStackSlot(src_index);
|
| } else if (op->IsRegister()) {
|
| Register reg = ToRegister(op);
|
| if (is_tagged) {
|
| @@ -414,7 +410,7 @@ void LCodeGen::CallCodeGeneric(Handle<Code> code,
|
| SafepointMode safepoint_mode) {
|
| ASSERT(instr != NULL);
|
|
|
| - Assembler::BlockConstPoolScope scope(masm_);
|
| + Assembler::BlockPoolsScope scope(masm_);
|
| __ Call(code, mode);
|
| RecordSafepointWithLazyDeopt(instr, safepoint_mode);
|
|
|
| @@ -445,8 +441,9 @@ void LCodeGen::DoCallNew(LCallNew* instr) {
|
|
|
| __ Mov(x0, instr->arity());
|
| // No cell in x2 for construct type feedback in optimized code.
|
| - Handle<Object> undefined_value(isolate()->factory()->undefined_value());
|
| - __ Mov(x2, Operand(undefined_value));
|
| + Handle<Object> megamorphic_symbol =
|
| + TypeFeedbackInfo::MegamorphicSentinel(isolate());
|
| + __ Mov(x2, Operand(megamorphic_symbol));
|
|
|
| CallConstructStub stub(NO_CALL_FUNCTION_FLAGS);
|
| CallCode(stub.GetCode(isolate()), RelocInfo::CONSTRUCT_CALL, instr);
|
| @@ -461,7 +458,7 @@ void LCodeGen::DoCallNewArray(LCallNewArray* instr) {
|
| ASSERT(ToRegister(instr->constructor()).is(x1));
|
|
|
| __ Mov(x0, Operand(instr->arity()));
|
| - __ Mov(x2, Operand(factory()->undefined_value()));
|
| + __ Mov(x2, Operand(TypeFeedbackInfo::MegamorphicSentinel(isolate())));
|
|
|
| ElementsKind kind = instr->hydrogen()->elements_kind();
|
| AllocationSiteOverrideMode override_mode =
|
| @@ -671,14 +668,14 @@ bool LCodeGen::GeneratePrologue() {
|
|
|
| // TODO(all): Add support for stop_t FLAG in DEBUG mode.
|
|
|
| - // Classic mode functions and builtins need to replace the receiver with the
|
| + // Sloppy mode functions and builtins need to replace the receiver with the
|
| // global proxy when called as functions (without an explicit receiver
|
| // object).
|
| if (info_->this_has_uses() &&
|
| - info_->is_classic_mode() &&
|
| + info_->strict_mode() == SLOPPY &&
|
| !info_->is_native()) {
|
| Label ok;
|
| - int receiver_offset = info_->scope()->num_parameters() * kXRegSizeInBytes;
|
| + int receiver_offset = info_->scope()->num_parameters() * kXRegSize;
|
| __ Peek(x10, receiver_offset);
|
| __ JumpIfNotRoot(x10, Heap::kUndefinedValueRootIndex, &ok);
|
|
|
| @@ -774,6 +771,13 @@ void LCodeGen::GenerateOsrPrologue() {
|
| }
|
|
|
|
|
| +void LCodeGen::GenerateBodyInstructionPre(LInstruction* instr) {
|
| + if (!instr->IsLazyBailout() && !instr->IsGap()) {
|
| + safepoints_.BumpLastLazySafepointIndex();
|
| + }
|
| +}
|
| +
|
| +
|
| bool LCodeGen::GenerateDeferredCode() {
|
| ASSERT(is_generating());
|
| if (deferred_.length() > 0) {
|
| @@ -837,18 +841,24 @@ bool LCodeGen::GenerateDeoptJumpTable() {
|
| __ bind(&table_start);
|
| Label needs_frame;
|
| for (int i = 0; i < deopt_jump_table_.length(); i++) {
|
| - __ Bind(&deopt_jump_table_[i].label);
|
| - Address entry = deopt_jump_table_[i].address;
|
| - Deoptimizer::BailoutType type = deopt_jump_table_[i].bailout_type;
|
| + __ Bind(&deopt_jump_table_[i]->label);
|
| + Address entry = deopt_jump_table_[i]->address;
|
| + Deoptimizer::BailoutType type = deopt_jump_table_[i]->bailout_type;
|
| int id = Deoptimizer::GetDeoptimizationId(isolate(), entry, type);
|
| if (id == Deoptimizer::kNotDeoptimizationEntry) {
|
| Comment(";;; jump table entry %d.", i);
|
| } else {
|
| Comment(";;; jump table entry %d: deoptimization bailout %d.", i, id);
|
| }
|
| - if (deopt_jump_table_[i].needs_frame) {
|
| + if (deopt_jump_table_[i]->needs_frame) {
|
| ASSERT(!info()->saves_caller_doubles());
|
| - __ Mov(__ Tmp0(), Operand(ExternalReference::ForDeoptEntry(entry)));
|
| +
|
| + UseScratchRegisterScope temps(masm());
|
| + Register stub_deopt_entry = temps.AcquireX();
|
| + Register stub_marker = temps.AcquireX();
|
| +
|
| + __ Mov(stub_deopt_entry,
|
| + Operand(ExternalReference::ForDeoptEntry(entry)));
|
| if (needs_frame.is_bound()) {
|
| __ B(&needs_frame);
|
| } else {
|
| @@ -856,12 +866,11 @@ bool LCodeGen::GenerateDeoptJumpTable() {
|
| // This variant of deopt can only be used with stubs. Since we don't
|
| // have a function pointer to install in the stack frame that we're
|
| // building, install a special marker there instead.
|
| - // TODO(jochen): Revisit the use of TmpX().
|
| ASSERT(info()->IsStub());
|
| - __ Mov(__ Tmp1(), Operand(Smi::FromInt(StackFrame::STUB)));
|
| - __ Push(lr, fp, cp, __ Tmp1());
|
| + __ Mov(stub_marker, Operand(Smi::FromInt(StackFrame::STUB)));
|
| + __ Push(lr, fp, cp, stub_marker);
|
| __ Add(fp, __ StackPointer(), 2 * kPointerSize);
|
| - __ Call(__ Tmp0());
|
| + __ Call(stub_deopt_entry);
|
| }
|
| } else {
|
| if (info()->saves_caller_doubles()) {
|
| @@ -1001,7 +1010,7 @@ void LCodeGen::DeoptimizeBranch(
|
| __ B(gt, ¬_zero);
|
| __ Mov(w1, FLAG_deopt_every_n_times);
|
| __ Str(w1, MemOperand(x0));
|
| - __ Pop(x0, x1, x2);
|
| + __ Pop(x2, x1, x0);
|
| ASSERT(frame_is_built_);
|
| __ Call(entry, RelocInfo::RUNTIME_ENTRY);
|
| __ Unreachable();
|
| @@ -1009,7 +1018,7 @@ void LCodeGen::DeoptimizeBranch(
|
| __ Bind(¬_zero);
|
| __ Str(w1, MemOperand(x0));
|
| __ Msr(NZCV, x2);
|
| - __ Pop(x0, x1, x2);
|
| + __ Pop(x2, x1, x0);
|
| }
|
|
|
| if (info()->ShouldTrapOnDeopt()) {
|
| @@ -1021,24 +1030,23 @@ void LCodeGen::DeoptimizeBranch(
|
|
|
| ASSERT(info()->IsStub() || frame_is_built_);
|
| // Go through jump table if we need to build frame, or restore caller doubles.
|
| - if (frame_is_built_ && !info()->saves_caller_doubles()) {
|
| - Label dont_deopt;
|
| - __ B(&dont_deopt, InvertBranchType(branch_type), reg, bit);
|
| + if (branch_type == always &&
|
| + frame_is_built_ && !info()->saves_caller_doubles()) {
|
| __ Call(entry, RelocInfo::RUNTIME_ENTRY);
|
| - __ Bind(&dont_deopt);
|
| } else {
|
| // We often have several deopts to the same entry, reuse the last
|
| // jump entry if this is the case.
|
| if (deopt_jump_table_.is_empty() ||
|
| - (deopt_jump_table_.last().address != entry) ||
|
| - (deopt_jump_table_.last().bailout_type != bailout_type) ||
|
| - (deopt_jump_table_.last().needs_frame != !frame_is_built_)) {
|
| - Deoptimizer::JumpTableEntry table_entry(entry,
|
| - bailout_type,
|
| - !frame_is_built_);
|
| + (deopt_jump_table_.last()->address != entry) ||
|
| + (deopt_jump_table_.last()->bailout_type != bailout_type) ||
|
| + (deopt_jump_table_.last()->needs_frame != !frame_is_built_)) {
|
| + Deoptimizer::JumpTableEntry* table_entry =
|
| + new(zone()) Deoptimizer::JumpTableEntry(entry,
|
| + bailout_type,
|
| + !frame_is_built_);
|
| deopt_jump_table_.Add(table_entry, zone());
|
| }
|
| - __ B(&deopt_jump_table_.last().label,
|
| + __ B(&deopt_jump_table_.last()->label,
|
| branch_type, reg, bit);
|
| }
|
| }
|
| @@ -1060,6 +1068,11 @@ void LCodeGen::DeoptimizeIfZero(Register rt, LEnvironment* environment) {
|
| }
|
|
|
|
|
| +void LCodeGen::DeoptimizeIfNotZero(Register rt, LEnvironment* environment) {
|
| + DeoptimizeBranch(environment, reg_not_zero, rt);
|
| +}
|
| +
|
| +
|
| void LCodeGen::DeoptimizeIfNegative(Register rt, LEnvironment* environment) {
|
| int sign_bit = rt.Is64Bits() ? kXSignBit : kWSignBit;
|
| DeoptimizeBranch(environment, reg_bit_set, rt, sign_bit);
|
| @@ -1507,23 +1520,22 @@ void LCodeGen::DoAllocate(LAllocate* instr) {
|
| __ Bind(deferred->exit());
|
|
|
| if (instr->hydrogen()->MustPrefillWithFiller()) {
|
| + Register filler_count = temp1;
|
| + Register filler = temp2;
|
| + Register untagged_result = ToRegister(instr->temp3());
|
| +
|
| if (instr->size()->IsConstantOperand()) {
|
| int32_t size = ToInteger32(LConstantOperand::cast(instr->size()));
|
| - __ Mov(temp1, size - kPointerSize);
|
| + __ Mov(filler_count, size / kPointerSize);
|
| } else {
|
| - __ Sub(temp1.W(), ToRegister32(instr->size()), kPointerSize);
|
| + __ Lsr(filler_count.W(), ToRegister32(instr->size()), kPointerSizeLog2);
|
| }
|
| - __ Sub(result, result, kHeapObjectTag);
|
| -
|
| - // TODO(jbramley): Optimize this loop using stp.
|
| - Label loop;
|
| - __ Bind(&loop);
|
| - __ Mov(temp2, Operand(isolate()->factory()->one_pointer_filler_map()));
|
| - __ Str(temp2, MemOperand(result, temp1));
|
| - __ Subs(temp1, temp1, kPointerSize);
|
| - __ B(ge, &loop);
|
|
|
| - __ Add(result, result, kHeapObjectTag);
|
| + __ Sub(untagged_result, result, kHeapObjectTag);
|
| + __ Mov(filler, Operand(isolate()->factory()->one_pointer_filler_map()));
|
| + __ FillFields(untagged_result, filler_count, filler);
|
| + } else {
|
| + ASSERT(instr->temp3() == NULL);
|
| }
|
| }
|
|
|
| @@ -2231,6 +2243,30 @@ void LCodeGen::DoClampTToUint8(LClampTToUint8* instr) {
|
| }
|
|
|
|
|
| +void LCodeGen::DoDoubleBits(LDoubleBits* instr) {
|
| + DoubleRegister value_reg = ToDoubleRegister(instr->value());
|
| + Register result_reg = ToRegister(instr->result());
|
| + if (instr->hydrogen()->bits() == HDoubleBits::HIGH) {
|
| + __ Fmov(result_reg, value_reg);
|
| + __ Mov(result_reg, Operand(result_reg, LSR, 32));
|
| + } else {
|
| + __ Fmov(result_reg.W(), value_reg.S());
|
| + }
|
| +}
|
| +
|
| +
|
| +void LCodeGen::DoConstructDouble(LConstructDouble* instr) {
|
| + Register hi_reg = ToRegister(instr->hi());
|
| + Register lo_reg = ToRegister(instr->lo());
|
| + Register temp = ToRegister(instr->temp());
|
| + DoubleRegister result_reg = ToDoubleRegister(instr->result());
|
| +
|
| + __ And(temp, lo_reg, Operand(0xffffffff));
|
| + __ Orr(temp, temp, Operand(hi_reg, LSL, 32));
|
| + __ Fmov(result_reg, temp);
|
| +}
|
| +
|
| +
|
| void LCodeGen::DoClassOfTestAndBranch(LClassOfTestAndBranch* instr) {
|
| Handle<String> class_name = instr->hydrogen()->class_name();
|
| Label* true_label = instr->TrueLabel(chunk_);
|
| @@ -2571,60 +2607,93 @@ void LCodeGen::DoDeoptimize(LDeoptimize* instr) {
|
| }
|
|
|
|
|
| -void LCodeGen::DoDivI(LDivI* instr) {
|
| - if (!instr->is_flooring() && instr->hydrogen()->RightIsPowerOf2()) {
|
| - HDiv* hdiv = instr->hydrogen();
|
| - Register dividend = ToRegister32(instr->left());
|
| - int32_t divisor = hdiv->right()->GetInteger32Constant();
|
| - Register result = ToRegister32(instr->result());
|
| - ASSERT(!result.is(dividend));
|
| +void LCodeGen::DoDivByPowerOf2I(LDivByPowerOf2I* instr) {
|
| + Register dividend = ToRegister32(instr->dividend());
|
| + int32_t divisor = instr->divisor();
|
| + Register result = ToRegister32(instr->result());
|
| + ASSERT(divisor == kMinInt || (divisor != 0 && IsPowerOf2(Abs(divisor))));
|
| + ASSERT(!result.is(dividend));
|
|
|
| - // Check for (0 / -x) that will produce negative zero.
|
| - if (hdiv->left()->RangeCanInclude(0) && divisor < 0 &&
|
| - hdiv->CheckFlag(HValue::kBailoutOnMinusZero)) {
|
| - __ Cmp(dividend, 0);
|
| - DeoptimizeIf(eq, instr->environment());
|
| - }
|
| - // Check for (kMinInt / -1).
|
| - if (hdiv->left()->RangeCanInclude(kMinInt) && divisor == -1 &&
|
| - hdiv->CheckFlag(HValue::kCanOverflow)) {
|
| - __ Cmp(dividend, kMinInt);
|
| - DeoptimizeIf(eq, instr->environment());
|
| - }
|
| - // Deoptimize if remainder will not be 0.
|
| - if (!hdiv->CheckFlag(HInstruction::kAllUsesTruncatingToInt32) &&
|
| - Abs(divisor) != 1) {
|
| - __ Tst(dividend, Abs(divisor) - 1);
|
| - DeoptimizeIf(ne, instr->environment());
|
| - }
|
| - if (divisor == -1) { // Nice shortcut, not needed for correctness.
|
| - __ Neg(result, dividend);
|
| - return;
|
| - }
|
| - int32_t shift = WhichPowerOf2(Abs(divisor));
|
| - if (shift == 0) {
|
| - __ Mov(result, dividend);
|
| - } else if (shift == 1) {
|
| - __ Add(result, dividend, Operand(dividend, LSR, 31));
|
| - } else {
|
| - __ Mov(result, Operand(dividend, ASR, 31));
|
| - __ Add(result, dividend, Operand(result, LSR, 32 - shift));
|
| - }
|
| - if (shift > 0) __ Mov(result, Operand(result, ASR, shift));
|
| - if (divisor < 0) __ Neg(result, result);
|
| + // Check for (0 / -x) that will produce negative zero.
|
| + HDiv* hdiv = instr->hydrogen();
|
| + if (hdiv->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0) {
|
| + __ Cmp(dividend, 0);
|
| + DeoptimizeIf(eq, instr->environment());
|
| + }
|
| + // Check for (kMinInt / -1).
|
| + if (hdiv->CheckFlag(HValue::kCanOverflow) && divisor == -1) {
|
| + __ Cmp(dividend, kMinInt);
|
| + DeoptimizeIf(eq, instr->environment());
|
| + }
|
| + // Deoptimize if remainder will not be 0.
|
| + if (!hdiv->CheckFlag(HInstruction::kAllUsesTruncatingToInt32) &&
|
| + divisor != 1 && divisor != -1) {
|
| + int32_t mask = divisor < 0 ? -(divisor + 1) : (divisor - 1);
|
| + __ Tst(dividend, mask);
|
| + DeoptimizeIf(ne, instr->environment());
|
| + }
|
| +
|
| + if (divisor == -1) { // Nice shortcut, not needed for correctness.
|
| + __ Neg(result, dividend);
|
| + return;
|
| + }
|
| + int32_t shift = WhichPowerOf2Abs(divisor);
|
| + if (shift == 0) {
|
| + __ Mov(result, dividend);
|
| + } else if (shift == 1) {
|
| + __ Add(result, dividend, Operand(dividend, LSR, 31));
|
| + } else {
|
| + __ Mov(result, Operand(dividend, ASR, 31));
|
| + __ Add(result, dividend, Operand(result, LSR, 32 - shift));
|
| + }
|
| + if (shift > 0) __ Mov(result, Operand(result, ASR, shift));
|
| + if (divisor < 0) __ Neg(result, result);
|
| +}
|
| +
|
| +
|
| +void LCodeGen::DoDivByConstI(LDivByConstI* instr) {
|
| + Register dividend = ToRegister32(instr->dividend());
|
| + int32_t divisor = instr->divisor();
|
| + Register result = ToRegister32(instr->result());
|
| + ASSERT(!AreAliased(dividend, result));
|
| +
|
| + if (divisor == 0) {
|
| + Deoptimize(instr->environment());
|
| return;
|
| }
|
|
|
| + // Check for (0 / -x) that will produce negative zero.
|
| + HDiv* hdiv = instr->hydrogen();
|
| + if (hdiv->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0) {
|
| + DeoptimizeIfZero(dividend, instr->environment());
|
| + }
|
| +
|
| + __ FlooringDiv(result, dividend, Abs(divisor));
|
| + __ Add(result, result, Operand(dividend, LSR, 31));
|
| + if (divisor < 0) __ Neg(result, result);
|
| +
|
| + if (!hdiv->CheckFlag(HInstruction::kAllUsesTruncatingToInt32)) {
|
| + Register temp = ToRegister32(instr->temp());
|
| + ASSERT(!AreAliased(dividend, result, temp));
|
| + __ Sxtw(dividend.X(), dividend);
|
| + __ Mov(temp, divisor);
|
| + __ Smsubl(temp.X(), result, temp, dividend.X());
|
| + DeoptimizeIfNotZero(temp, instr->environment());
|
| + }
|
| +}
|
| +
|
| +
|
| +void LCodeGen::DoDivI(LDivI* instr) {
|
| + HBinaryOperation* hdiv = instr->hydrogen();
|
| Register dividend = ToRegister32(instr->left());
|
| Register divisor = ToRegister32(instr->right());
|
| Register result = ToRegister32(instr->result());
|
| - HValue* hdiv = instr->hydrogen_value();
|
|
|
| // Issue the division first, and then check for any deopt cases whilst the
|
| // result is computed.
|
| __ Sdiv(result, dividend, divisor);
|
|
|
| - if (hdiv->CheckFlag(HInstruction::kAllUsesTruncatingToInt32)) {
|
| + if (hdiv->CheckFlag(HValue::kAllUsesTruncatingToInt32)) {
|
| ASSERT_EQ(NULL, instr->temp());
|
| return;
|
| }
|
| @@ -2716,7 +2785,7 @@ void LCodeGen::DoFunctionLiteral(LFunctionLiteral* instr) {
|
| // space for nested functions that don't need literals cloning.
|
| bool pretenure = instr->hydrogen()->pretenure();
|
| if (!pretenure && instr->hydrogen()->has_no_literals()) {
|
| - FastNewClosureStub stub(instr->hydrogen()->language_mode(),
|
| + FastNewClosureStub stub(instr->hydrogen()->strict_mode(),
|
| instr->hydrogen()->is_generator());
|
| __ Mov(x2, Operand(instr->hydrogen()->shared_info()));
|
| CallCode(stub.GetCode(isolate()), RelocInfo::CODE_TARGET, instr);
|
| @@ -2800,7 +2869,7 @@ void LCodeGen::DoGetCachedArrayIndex(LGetCachedArrayIndex* instr) {
|
| __ AssertString(input);
|
|
|
| // Assert that we can use a W register load to get the hash.
|
| - ASSERT((String::kHashShift + String::kArrayIndexValueBits) < kWRegSize);
|
| + ASSERT((String::kHashShift + String::kArrayIndexValueBits) < kWRegSizeInBits);
|
| __ Ldr(result.W(), FieldMemOperand(input, String::kHashFieldOffset));
|
| __ IndexFromHash(result, result);
|
| }
|
| @@ -3035,17 +3104,6 @@ void LCodeGen::DoInteger32ToDouble(LInteger32ToDouble* instr) {
|
| }
|
|
|
|
|
| -void LCodeGen::DoInteger32ToSmi(LInteger32ToSmi* instr) {
|
| - // A64 smis can represent all Integer32 values, so this cannot deoptimize.
|
| - ASSERT(!instr->hydrogen()->value()->HasRange() ||
|
| - instr->hydrogen()->value()->range()->IsInSmiRange());
|
| -
|
| - Register value = ToRegister32(instr->value());
|
| - Register result = ToRegister(instr->result());
|
| - __ SmiTag(result, value.X());
|
| -}
|
| -
|
| -
|
| void LCodeGen::DoInvokeFunction(LInvokeFunction* instr) {
|
| ASSERT(ToRegister(instr->context()).is(cp));
|
| // The function is required to be in x1.
|
| @@ -3409,7 +3467,7 @@ void LCodeGen::DoLoadKeyedExternal(LLoadKeyedExternal* instr) {
|
| case FAST_ELEMENTS:
|
| case FAST_SMI_ELEMENTS:
|
| case DICTIONARY_ELEMENTS:
|
| - case NON_STRICT_ARGUMENTS_ELEMENTS:
|
| + case SLOPPY_ARGUMENTS_ELEMENTS:
|
| UNREACHABLE();
|
| break;
|
| }
|
| @@ -3672,8 +3730,7 @@ void LCodeGen::DoDeferredMathAbsTagged(LMathAbsTagged* instr,
|
| Register input = ToRegister(instr->value());
|
| __ JumpIfSmi(result, &result_ok);
|
| __ Cmp(input, result);
|
| - // TODO(all): Shouldn't we assert here?
|
| - DeoptimizeIf(ne, instr->environment());
|
| + __ Assert(eq, kUnexpectedValue);
|
| __ Bind(&result_ok);
|
| }
|
|
|
| @@ -3723,12 +3780,7 @@ void LCodeGen::DoMathAbsTagged(LMathAbsTagged* instr) {
|
| // case in DoMathAbs, except that it operates on 64-bit values.
|
| STATIC_ASSERT((kSmiValueSize == 32) && (kSmiShift == 32) && (kSmiTag == 0));
|
|
|
| - // TODO(jbramley): We can't use JumpIfNotSmi here because the tbz it uses
|
| - // doesn't always have enough range. Consider making a variant of it, or a
|
| - // TestIsSmi helper.
|
| - STATIC_ASSERT(kSmiTag == 0);
|
| - __ Tst(input, kSmiTagMask);
|
| - __ B(ne, deferred->entry());
|
| + __ JumpIfNotSmi(input, deferred->entry());
|
|
|
| __ Abs(result, input, NULL, &done);
|
|
|
| @@ -3787,44 +3839,103 @@ void LCodeGen::DoMathFloor(LMathFloor* instr) {
|
| }
|
|
|
|
|
| -void LCodeGen::DoMathFloorOfDiv(LMathFloorOfDiv* instr) {
|
| +void LCodeGen::DoFlooringDivByPowerOf2I(LFlooringDivByPowerOf2I* instr) {
|
| + Register dividend = ToRegister32(instr->dividend());
|
| Register result = ToRegister32(instr->result());
|
| - Register left = ToRegister32(instr->left());
|
| - Register right = ToRegister32(instr->right());
|
| + int32_t divisor = instr->divisor();
|
| +
|
| + // If the divisor is positive, things are easy: There can be no deopts and we
|
| + // can simply do an arithmetic right shift.
|
| + if (divisor == 1) return;
|
| + int32_t shift = WhichPowerOf2Abs(divisor);
|
| + if (divisor > 1) {
|
| + __ Mov(result, Operand(dividend, ASR, shift));
|
| + return;
|
| + }
|
| +
|
| + // If the divisor is negative, we have to negate and handle edge cases.
|
| + Label not_kmin_int, done;
|
| + __ Negs(result, dividend);
|
| + if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
|
| + DeoptimizeIf(eq, instr->environment());
|
| + }
|
| + if (instr->hydrogen()->CheckFlag(HValue::kLeftCanBeMinInt)) {
|
| + // Note that we could emit branch-free code, but that would need one more
|
| + // register.
|
| + if (divisor == -1) {
|
| + DeoptimizeIf(vs, instr->environment());
|
| + } else {
|
| + __ B(vc, ¬_kmin_int);
|
| + __ Mov(result, kMinInt / divisor);
|
| + __ B(&done);
|
| + }
|
| + }
|
| + __ bind(¬_kmin_int);
|
| + __ Mov(result, Operand(dividend, ASR, shift));
|
| + __ bind(&done);
|
| +}
|
| +
|
| +
|
| +void LCodeGen::DoFlooringDivByConstI(LFlooringDivByConstI* instr) {
|
| + Register dividend = ToRegister32(instr->dividend());
|
| + int32_t divisor = instr->divisor();
|
| + Register result = ToRegister32(instr->result());
|
| + ASSERT(!AreAliased(dividend, result));
|
| +
|
| + if (divisor == 0) {
|
| + Deoptimize(instr->environment());
|
| + return;
|
| + }
|
| +
|
| + // Check for (0 / -x) that will produce negative zero.
|
| + HMathFloorOfDiv* hdiv = instr->hydrogen();
|
| + if (hdiv->CheckFlag(HValue::kBailoutOnMinusZero) && divisor < 0) {
|
| + __ Cmp(dividend, 0);
|
| + DeoptimizeIf(eq, instr->environment());
|
| + }
|
| +
|
| + __ FlooringDiv(result, dividend, divisor);
|
| +}
|
| +
|
| +
|
| +void LCodeGen::DoFlooringDivI(LFlooringDivI* instr) {
|
| + Register dividend = ToRegister32(instr->dividend());
|
| + Register divisor = ToRegister32(instr->divisor());
|
| Register remainder = ToRegister32(instr->temp());
|
| + Register result = ToRegister32(instr->result());
|
|
|
| // This can't cause an exception on ARM, so we can speculatively
|
| // execute it already now.
|
| - __ Sdiv(result, left, right);
|
| + __ Sdiv(result, dividend, divisor);
|
|
|
| // Check for x / 0.
|
| - DeoptimizeIfZero(right, instr->environment());
|
| + DeoptimizeIfZero(divisor, instr->environment());
|
|
|
| // Check for (kMinInt / -1).
|
| if (instr->hydrogen()->CheckFlag(HValue::kCanOverflow)) {
|
| - // The V flag will be set iff left == kMinInt.
|
| - __ Cmp(left, 1);
|
| - __ Ccmp(right, -1, NoFlag, vs);
|
| + // The V flag will be set iff dividend == kMinInt.
|
| + __ Cmp(dividend, 1);
|
| + __ Ccmp(divisor, -1, NoFlag, vs);
|
| DeoptimizeIf(eq, instr->environment());
|
| }
|
|
|
| // Check for (0 / -x) that will produce negative zero.
|
| if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
|
| - __ Cmp(right, 0);
|
| - __ Ccmp(left, 0, ZFlag, mi);
|
| - // "right" can't be null because the code would have already been
|
| - // deoptimized. The Z flag is set only if (right < 0) and (left == 0).
|
| + __ Cmp(divisor, 0);
|
| + __ Ccmp(dividend, 0, ZFlag, mi);
|
| + // "divisor" can't be null because the code would have already been
|
| + // deoptimized. The Z flag is set only if (divisor < 0) and (dividend == 0).
|
| // In this case we need to deoptimize to produce a -0.
|
| DeoptimizeIf(eq, instr->environment());
|
| }
|
|
|
| Label done;
|
| // If both operands have the same sign then we are done.
|
| - __ Eor(remainder, left, right);
|
| + __ Eor(remainder, dividend, divisor);
|
| __ Tbz(remainder, kWSignBit, &done);
|
|
|
| // Check if the result needs to be corrected.
|
| - __ Msub(remainder, result, right, left);
|
| + __ Msub(remainder, result, divisor, dividend);
|
| __ Cbz(remainder, &done);
|
| __ Sub(result, result, 1);
|
|
|
| @@ -3865,9 +3976,7 @@ void LCodeGen::DoMathPowHalf(LMathPowHalf* instr) {
|
| __ B(&done, eq);
|
|
|
| // Add +0.0 to convert -0.0 to +0.0.
|
| - // TODO(jbramley): A constant zero register would be helpful here.
|
| - __ Fmov(double_scratch(), 0.0);
|
| - __ Fadd(double_scratch(), input, double_scratch());
|
| + __ Fadd(double_scratch(), input, fp_zero);
|
| __ Fsqrt(result, double_scratch());
|
|
|
| __ Bind(&done);
|
| @@ -4013,58 +4122,91 @@ void LCodeGen::DoMathMinMax(LMathMinMax* instr) {
|
| }
|
|
|
|
|
| -void LCodeGen::DoModI(LModI* instr) {
|
| +void LCodeGen::DoModByPowerOf2I(LModByPowerOf2I* instr) {
|
| + Register dividend = ToRegister32(instr->dividend());
|
| + int32_t divisor = instr->divisor();
|
| + ASSERT(dividend.is(ToRegister32(instr->result())));
|
| +
|
| + // Theoretically, a variation of the branch-free code for integer division by
|
| + // a power of 2 (calculating the remainder via an additional multiplication
|
| + // (which gets simplified to an 'and') and subtraction) should be faster, and
|
| + // this is exactly what GCC and clang emit. Nevertheless, benchmarks seem to
|
| + // indicate that positive dividends are heavily favored, so the branching
|
| + // version performs better.
|
| HMod* hmod = instr->hydrogen();
|
| - HValue* hleft = hmod->left();
|
| - HValue* hright = hmod->right();
|
| + int32_t mask = divisor < 0 ? -(divisor + 1) : (divisor - 1);
|
| + Label dividend_is_not_negative, done;
|
| + if (hmod->CheckFlag(HValue::kLeftCanBeNegative)) {
|
| + __ Cmp(dividend, 0);
|
| + __ B(pl, ÷nd_is_not_negative);
|
| + // Note that this is correct even for kMinInt operands.
|
| + __ Neg(dividend, dividend);
|
| + __ And(dividend, dividend, Operand(mask));
|
| + __ Negs(dividend, dividend);
|
| + if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) {
|
| + DeoptimizeIf(eq, instr->environment());
|
| + }
|
| + __ B(&done);
|
| + }
|
|
|
| - Label done;
|
| + __ bind(÷nd_is_not_negative);
|
| + __ And(dividend, dividend, Operand(mask));
|
| + __ bind(&done);
|
| +}
|
| +
|
| +
|
| +void LCodeGen::DoModByConstI(LModByConstI* instr) {
|
| + Register dividend = ToRegister32(instr->dividend());
|
| + int32_t divisor = instr->divisor();
|
| Register result = ToRegister32(instr->result());
|
| + Register temp = ToRegister32(instr->temp());
|
| + ASSERT(!AreAliased(dividend, result, temp));
|
| +
|
| + if (divisor == 0) {
|
| + Deoptimize(instr->environment());
|
| + return;
|
| + }
|
| +
|
| + __ FlooringDiv(result, dividend, Abs(divisor));
|
| + __ Add(result, result, Operand(dividend, LSR, 31));
|
| + __ Sxtw(dividend.X(), dividend);
|
| + __ Mov(temp, Abs(divisor));
|
| + __ Smsubl(result.X(), result, temp, dividend.X());
|
| +
|
| + // Check for negative zero.
|
| + HMod* hmod = instr->hydrogen();
|
| + if (hmod->CheckFlag(HValue::kBailoutOnMinusZero)) {
|
| + Label remainder_not_zero;
|
| + __ Cbnz(result, &remainder_not_zero);
|
| + DeoptimizeIfNegative(dividend, instr->environment());
|
| + __ bind(&remainder_not_zero);
|
| + }
|
| +}
|
| +
|
| +
|
| +void LCodeGen::DoModI(LModI* instr) {
|
| Register dividend = ToRegister32(instr->left());
|
| + Register divisor = ToRegister32(instr->right());
|
| + Register result = ToRegister32(instr->result());
|
|
|
| - bool need_minus_zero_check = (hmod->CheckFlag(HValue::kBailoutOnMinusZero) &&
|
| - hleft->CanBeNegative() && hmod->CanBeZero());
|
| -
|
| - if (hmod->RightIsPowerOf2()) {
|
| - // Note: The code below even works when right contains kMinInt.
|
| - int32_t divisor = Abs(hright->GetInteger32Constant());
|
| -
|
| - if (hleft->CanBeNegative()) {
|
| - __ Cmp(dividend, 0);
|
| - __ Cneg(result, dividend, mi);
|
| - __ And(result, result, divisor - 1);
|
| - __ Cneg(result, result, mi);
|
| - if (need_minus_zero_check) {
|
| - __ Cbnz(result, &done);
|
| - // The result is 0. Deoptimize if the dividend was negative.
|
| - DeoptimizeIf(mi, instr->environment());
|
| - }
|
| + Label deopt, done;
|
| + // modulo = dividend - quotient * divisor
|
| + __ Sdiv(result, dividend, divisor);
|
| + if (instr->hydrogen()->CheckFlag(HValue::kCanBeDivByZero)) {
|
| + // Combine the deoptimization sites.
|
| + Label ok;
|
| + __ Cbnz(divisor, &ok);
|
| + __ Bind(&deopt);
|
| + Deoptimize(instr->environment());
|
| + __ Bind(&ok);
|
| + }
|
| + __ Msub(result, result, divisor, dividend);
|
| + if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
|
| + __ Cbnz(result, &done);
|
| + if (deopt.is_bound()) { // TODO(all) This is a hack, remove this...
|
| + __ Tbnz(dividend, kWSignBit, &deopt);
|
| } else {
|
| - __ And(result, dividend, divisor - 1);
|
| - }
|
| -
|
| - } else {
|
| - Label deopt;
|
| - Register divisor = ToRegister32(instr->right());
|
| - // Compute:
|
| - // modulo = dividend - quotient * divisor
|
| - __ Sdiv(result, dividend, divisor);
|
| - if (hright->CanBeZero()) {
|
| - // Combine the deoptimization sites.
|
| - Label ok;
|
| - __ Cbnz(divisor, &ok);
|
| - __ Bind(&deopt);
|
| - Deoptimize(instr->environment());
|
| - __ Bind(&ok);
|
| - }
|
| - __ Msub(result, result, divisor, dividend);
|
| - if (need_minus_zero_check) {
|
| - __ Cbnz(result, &done);
|
| - if (deopt.is_bound()) {
|
| - __ Tbnz(dividend, kWSignBit, &deopt);
|
| - } else {
|
| - DeoptimizeIfNegative(dividend, instr->environment());
|
| - }
|
| + DeoptimizeIfNegative(dividend, instr->environment());
|
| }
|
| }
|
| __ Bind(&done);
|
| @@ -4174,7 +4316,7 @@ void LCodeGen::DoMulI(LMulI* instr) {
|
| bool bailout_on_minus_zero =
|
| instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero);
|
|
|
| - if (bailout_on_minus_zero) {
|
| + if (bailout_on_minus_zero && !left.Is(right)) {
|
| // If one operand is zero and the other is negative, the result is -0.
|
| // - Set Z (eq) if either left or right, or both, are 0.
|
| __ Cmp(left, 0);
|
| @@ -4204,7 +4346,7 @@ void LCodeGen::DoMulS(LMulS* instr) {
|
| bool bailout_on_minus_zero =
|
| instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero);
|
|
|
| - if (bailout_on_minus_zero) {
|
| + if (bailout_on_minus_zero && !left.Is(right)) {
|
| // If one operand is zero and the other is negative, the result is -0.
|
| // - Set Z (eq) if either left or right, or both, are 0.
|
| __ Cmp(left, 0);
|
| @@ -4222,10 +4364,25 @@ void LCodeGen::DoMulS(LMulS* instr) {
|
| __ SmiTag(result);
|
| DeoptimizeIf(ne, instr->environment());
|
| } else {
|
| - // TODO(jbramley): This could be rewritten to support UseRegisterAtStart.
|
| - ASSERT(!AreAliased(result, right));
|
| - __ SmiUntag(result, left);
|
| - __ Mul(result, result, right);
|
| + if (AreAliased(result, left, right)) {
|
| + // All three registers are the same: half untag the input and then
|
| + // multiply, giving a tagged result.
|
| + STATIC_ASSERT((kSmiShift % 2) == 0);
|
| + __ Asr(result, left, kSmiShift / 2);
|
| + __ Mul(result, result, result);
|
| + } else if (result.Is(left) && !left.Is(right)) {
|
| + // Registers result and left alias, right is distinct: untag left into
|
| + // result, and then multiply by right, giving a tagged result.
|
| + __ SmiUntag(result, left);
|
| + __ Mul(result, result, right);
|
| + } else {
|
| + ASSERT(!left.Is(result));
|
| + // Registers result and right alias, left is distinct, or all registers
|
| + // are distinct: untag right into result, and then multiply by left,
|
| + // giving a tagged result.
|
| + __ SmiUntag(result, right);
|
| + __ Mul(result, left, result);
|
| + }
|
| }
|
| }
|
|
|
| @@ -4488,8 +4645,7 @@ MemOperand LCodeGen::BuildSeqStringOperand(Register string,
|
| STATIC_ASSERT(kCharSize == 1);
|
| return FieldMemOperand(string, SeqString::kHeaderSize + offset);
|
| }
|
| - ASSERT(!temp.is(string));
|
| - ASSERT(!temp.is(ToRegister(index)));
|
| +
|
| if (encoding == String::ONE_BYTE_ENCODING) {
|
| __ Add(temp, string, Operand(ToRegister32(index), SXTW));
|
| } else {
|
| @@ -4507,15 +4663,21 @@ void LCodeGen::DoSeqStringGetChar(LSeqStringGetChar* instr) {
|
| Register temp = ToRegister(instr->temp());
|
|
|
| if (FLAG_debug_code) {
|
| - __ Ldr(temp, FieldMemOperand(string, HeapObject::kMapOffset));
|
| - __ Ldrb(temp, FieldMemOperand(temp, Map::kInstanceTypeOffset));
|
| + // Even though this lithium instruction comes with a temp register, we
|
| + // can't use it here because we want to use "AtStart" constraints on the
|
| + // inputs and the debug code here needs a scratch register.
|
| + UseScratchRegisterScope temps(masm());
|
| + Register dbg_temp = temps.AcquireX();
|
|
|
| - __ And(temp, temp,
|
| + __ Ldr(dbg_temp, FieldMemOperand(string, HeapObject::kMapOffset));
|
| + __ Ldrb(dbg_temp, FieldMemOperand(dbg_temp, Map::kInstanceTypeOffset));
|
| +
|
| + __ And(dbg_temp, dbg_temp,
|
| Operand(kStringRepresentationMask | kStringEncodingMask));
|
| static const uint32_t one_byte_seq_type = kSeqStringTag | kOneByteStringTag;
|
| static const uint32_t two_byte_seq_type = kSeqStringTag | kTwoByteStringTag;
|
| - __ Cmp(temp, Operand(encoding == String::ONE_BYTE_ENCODING
|
| - ? one_byte_seq_type : two_byte_seq_type));
|
| + __ Cmp(dbg_temp, Operand(encoding == String::ONE_BYTE_ENCODING
|
| + ? one_byte_seq_type : two_byte_seq_type));
|
| __ Check(eq, kUnexpectedStringType);
|
| }
|
|
|
| @@ -4557,8 +4719,14 @@ void LCodeGen::DoSeqStringSetChar(LSeqStringSetChar* instr) {
|
|
|
|
|
| void LCodeGen::DoSmiTag(LSmiTag* instr) {
|
| - ASSERT(!instr->hydrogen_value()->CheckFlag(HValue::kCanOverflow));
|
| - __ SmiTag(ToRegister(instr->result()), ToRegister(instr->value()));
|
| + HChange* hchange = instr->hydrogen();
|
| + Register input = ToRegister(instr->value());
|
| + Register output = ToRegister(instr->result());
|
| + if (hchange->CheckFlag(HValue::kCanOverflow) &&
|
| + hchange->value()->CheckFlag(HValue::kUint32)) {
|
| + DeoptimizeIfNegative(input.W(), instr->environment());
|
| + }
|
| + __ SmiTag(output, input);
|
| }
|
|
|
|
|
| @@ -4920,7 +5088,7 @@ void LCodeGen::DoStoreKeyedExternal(LStoreKeyedExternal* instr) {
|
| case FAST_HOLEY_ELEMENTS:
|
| case FAST_HOLEY_SMI_ELEMENTS:
|
| case DICTIONARY_ELEMENTS:
|
| - case NON_STRICT_ARGUMENTS_ELEMENTS:
|
| + case SLOPPY_ARGUMENTS_ELEMENTS:
|
| UNREACHABLE();
|
| break;
|
| }
|
| @@ -4931,7 +5099,7 @@ void LCodeGen::DoStoreKeyedExternal(LStoreKeyedExternal* instr) {
|
| void LCodeGen::DoStoreKeyedFixedDouble(LStoreKeyedFixedDouble* instr) {
|
| Register elements = ToRegister(instr->elements());
|
| DoubleRegister value = ToDoubleRegister(instr->value());
|
| - Register store_base = ToRegister(instr->temp());
|
| + Register store_base = no_reg;
|
| int offset = 0;
|
|
|
| if (instr->key()->IsConstantOperand()) {
|
| @@ -4943,6 +5111,7 @@ void LCodeGen::DoStoreKeyedFixedDouble(LStoreKeyedFixedDouble* instr) {
|
| instr->additional_index());
|
| store_base = elements;
|
| } else {
|
| + store_base = ToRegister(instr->temp());
|
| Register key = ToRegister(instr->key());
|
| bool key_is_tagged = instr->hydrogen()->key()->representation().IsSmi();
|
| CalcKeyedArrayBaseRegister(store_base, elements, key, key_is_tagged,
|
| @@ -4965,17 +5134,23 @@ void LCodeGen::DoStoreKeyedFixedDouble(LStoreKeyedFixedDouble* instr) {
|
| void LCodeGen::DoStoreKeyedFixed(LStoreKeyedFixed* instr) {
|
| Register value = ToRegister(instr->value());
|
| Register elements = ToRegister(instr->elements());
|
| - Register store_base = ToRegister(instr->temp());
|
| + Register scratch = no_reg;
|
| + Register store_base = no_reg;
|
| Register key = no_reg;
|
| int offset = 0;
|
|
|
| + if (!instr->key()->IsConstantOperand() ||
|
| + instr->hydrogen()->NeedsWriteBarrier()) {
|
| + scratch = ToRegister(instr->temp());
|
| + }
|
| +
|
| if (instr->key()->IsConstantOperand()) {
|
| - ASSERT(!instr->hydrogen()->NeedsWriteBarrier());
|
| LConstantOperand* const_operand = LConstantOperand::cast(instr->key());
|
| offset = FixedArray::OffsetOfElementAt(ToInteger32(const_operand) +
|
| instr->additional_index());
|
| store_base = elements;
|
| } else {
|
| + store_base = scratch;
|
| key = ToRegister(instr->key());
|
| bool key_is_tagged = instr->hydrogen()->key()->representation().IsSmi();
|
| CalcKeyedArrayBaseRegister(store_base, elements, key, key_is_tagged,
|
| @@ -4994,13 +5169,16 @@ void LCodeGen::DoStoreKeyedFixed(LStoreKeyedFixed* instr) {
|
| }
|
|
|
| if (instr->hydrogen()->NeedsWriteBarrier()) {
|
| + ASSERT(representation.IsTagged());
|
| + // This assignment may cause element_addr to alias store_base.
|
| + Register element_addr = scratch;
|
| SmiCheck check_needed =
|
| instr->hydrogen()->value()->IsHeapObject()
|
| ? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
|
| // Compute address of modified element and store it into key register.
|
| - __ Add(key, store_base, offset - kHeapObjectTag);
|
| - __ RecordWrite(elements, key, value, GetLinkRegisterState(), kSaveFPRegs,
|
| - EMIT_REMEMBERED_SET, check_needed);
|
| + __ Add(element_addr, store_base, offset - kHeapObjectTag);
|
| + __ RecordWrite(elements, element_addr, value, GetLinkRegisterState(),
|
| + kSaveFPRegs, EMIT_REMEMBERED_SET, check_needed);
|
| }
|
| }
|
|
|
| @@ -5011,43 +5189,27 @@ void LCodeGen::DoStoreKeyedGeneric(LStoreKeyedGeneric* instr) {
|
| ASSERT(ToRegister(instr->key()).Is(x1));
|
| ASSERT(ToRegister(instr->value()).Is(x0));
|
|
|
| - Handle<Code> ic = (instr->strict_mode_flag() == kStrictMode)
|
| + Handle<Code> ic = instr->strict_mode() == STRICT
|
| ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict()
|
| : isolate()->builtins()->KeyedStoreIC_Initialize();
|
| CallCode(ic, RelocInfo::CODE_TARGET, instr);
|
| }
|
|
|
|
|
| -// TODO(jbramley): Once the merge is done and we're tracking bleeding_edge, try
|
| -// to tidy up this function.
|
| void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) {
|
| Representation representation = instr->representation();
|
|
|
| Register object = ToRegister(instr->object());
|
| - Register temp0 = ToRegister(instr->temp0());
|
| - Register temp1 = ToRegister(instr->temp1());
|
| HObjectAccess access = instr->hydrogen()->access();
|
| + Handle<Map> transition = instr->transition();
|
| int offset = access.offset();
|
|
|
| if (access.IsExternalMemory()) {
|
| + ASSERT(transition.is_null());
|
| + ASSERT(!instr->hydrogen()->NeedsWriteBarrier());
|
| Register value = ToRegister(instr->value());
|
| __ Store(value, MemOperand(object, offset), representation);
|
| return;
|
| - }
|
| -
|
| - Handle<Map> transition = instr->transition();
|
| - SmiCheck check_needed =
|
| - instr->hydrogen()->value()->IsHeapObject()
|
| - ? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
|
| -
|
| - if (FLAG_track_heap_object_fields && representation.IsHeapObject()) {
|
| - Register value = ToRegister(instr->value());
|
| - if (!instr->hydrogen()->value()->type().IsHeapObject()) {
|
| - DeoptimizeIfSmi(value, instr->environment());
|
| -
|
| - // We know that value is a smi now, so we can omit the check below.
|
| - check_needed = OMIT_SMI_CHECK;
|
| - }
|
| } else if (representation.IsDouble()) {
|
| ASSERT(transition.is_null());
|
| ASSERT(access.IsInobject());
|
| @@ -5057,9 +5219,22 @@ void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) {
|
| return;
|
| }
|
|
|
| + Register value = ToRegister(instr->value());
|
| +
|
| + SmiCheck check_needed = instr->hydrogen()->value()->IsHeapObject()
|
| + ? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
|
| +
|
| + if (representation.IsHeapObject() &&
|
| + !instr->hydrogen()->value()->type().IsHeapObject()) {
|
| + DeoptimizeIfSmi(value, instr->environment());
|
| +
|
| + // We know that value is a smi now, so we can omit the check below.
|
| + check_needed = OMIT_SMI_CHECK;
|
| + }
|
| +
|
| if (!transition.is_null()) {
|
| // Store the new map value.
|
| - Register new_map_value = temp0;
|
| + Register new_map_value = ToRegister(instr->temp0());
|
| __ Mov(new_map_value, Operand(transition));
|
| __ Str(new_map_value, FieldMemOperand(object, HeapObject::kMapOffset));
|
| if (instr->hydrogen()->NeedsWriteBarrierForMap()) {
|
| @@ -5067,7 +5242,7 @@ void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) {
|
| __ RecordWriteField(object,
|
| HeapObject::kMapOffset,
|
| new_map_value,
|
| - temp1,
|
| + ToRegister(instr->temp1()),
|
| GetLinkRegisterState(),
|
| kSaveFPRegs,
|
| OMIT_REMEMBERED_SET,
|
| @@ -5076,21 +5251,28 @@ void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) {
|
| }
|
|
|
| // Do the store.
|
| - Register value = ToRegister(instr->value());
|
| Register destination;
|
| if (access.IsInobject()) {
|
| destination = object;
|
| } else {
|
| + Register temp0 = ToRegister(instr->temp0());
|
| __ Ldr(temp0, FieldMemOperand(object, JSObject::kPropertiesOffset));
|
| destination = temp0;
|
| }
|
|
|
| if (representation.IsSmi() &&
|
| - instr->hydrogen()->value()->representation().IsInteger32()) {
|
| + instr->hydrogen()->value()->representation().IsInteger32()) {
|
| ASSERT(instr->hydrogen()->store_mode() == STORE_TO_INITIALIZED_ENTRY);
|
| #ifdef DEBUG
|
| - __ Ldr(temp1, FieldMemOperand(destination, offset));
|
| - __ AssertSmi(temp1);
|
| + Register temp0 = ToRegister(instr->temp0());
|
| + __ Ldr(temp0, FieldMemOperand(destination, offset));
|
| + __ AssertSmi(temp0);
|
| + // If destination aliased temp0, restore it to the address calculated
|
| + // earlier.
|
| + if (destination.Is(temp0)) {
|
| + ASSERT(!access.IsInobject());
|
| + __ Ldr(destination, FieldMemOperand(object, JSObject::kPropertiesOffset));
|
| + }
|
| #endif
|
| STATIC_ASSERT(kSmiValueSize == 32 && kSmiShift == 32 && kSmiTag == 0);
|
| __ Store(value, UntagSmiFieldMemOperand(destination, offset),
|
| @@ -5101,8 +5283,8 @@ void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) {
|
| if (instr->hydrogen()->NeedsWriteBarrier()) {
|
| __ RecordWriteField(destination,
|
| offset,
|
| - value, // Clobbered.
|
| - temp1, // Clobbered.
|
| + value, // Clobbered.
|
| + ToRegister(instr->temp1()), // Clobbered.
|
| GetLinkRegisterState(),
|
| kSaveFPRegs,
|
| EMIT_REMEMBERED_SET,
|
| @@ -5118,8 +5300,7 @@ void LCodeGen::DoStoreNamedGeneric(LStoreNamedGeneric* instr) {
|
|
|
| // Name must be in x2.
|
| __ Mov(x2, Operand(instr->name()));
|
| - Handle<Code> ic = StoreIC::initialize_stub(isolate(),
|
| - instr->strict_mode_flag());
|
| + Handle<Code> ic = StoreIC::initialize_stub(isolate(), instr->strict_mode());
|
| CallCode(ic, RelocInfo::CODE_TARGET, instr);
|
| }
|
|
|
| @@ -5580,21 +5761,6 @@ void LCodeGen::DoUint32ToDouble(LUint32ToDouble* instr) {
|
| }
|
|
|
|
|
| -void LCodeGen::DoUint32ToSmi(LUint32ToSmi* instr) {
|
| - Register value = ToRegister(instr->value());
|
| - Register result = ToRegister(instr->result());
|
| -
|
| - if (!instr->hydrogen()->value()->HasRange() ||
|
| - !instr->hydrogen()->value()->range()->IsInSmiRange() ||
|
| - instr->hydrogen()->value()->range()->upper() == kMaxInt) {
|
| - // The Range class can't express upper bounds in the (kMaxInt, kMaxUint32]
|
| - // interval, so we treat kMaxInt as a sentinel for this entire interval.
|
| - DeoptimizeIfNegative(value.W(), instr->environment());
|
| - }
|
| - __ SmiTag(result, value);
|
| -}
|
| -
|
| -
|
| void LCodeGen::DoCheckMapValue(LCheckMapValue* instr) {
|
| Register object = ToRegister(instr->value());
|
| Register map = ToRegister(instr->map());
|
|
|