Index: src/mips/lithium-codegen-mips.cc |
diff --git a/src/mips/lithium-codegen-mips.cc b/src/mips/lithium-codegen-mips.cc |
index 86669f48f9c6ee1ba1303aaad65763df60090608..5469f6df9bbd179d0392d378131a5ef756657f5a 100644 |
--- a/src/mips/lithium-codegen-mips.cc |
+++ b/src/mips/lithium-codegen-mips.cc |
@@ -147,14 +147,21 @@ bool LCodeGen::GeneratePrologue() { |
info()->set_prologue_offset(masm_->pc_offset()); |
if (NeedsEagerFrame()) { |
- // The following three instructions must remain together and unmodified for |
- // code aging to work properly. |
- __ Push(ra, fp, cp, a1); |
- // Add unused load of ip to ensure prologue sequence is identical for |
- // full-codegen and lithium-codegen. |
- __ LoadRoot(at, Heap::kUndefinedValueRootIndex); |
- // Adj. FP to point to saved FP. |
- __ Addu(fp, sp, Operand(2 * kPointerSize)); |
+ if (info()->IsStub()) { |
+ __ Push(ra, fp, cp); |
+ __ Push(Smi::FromInt(StackFrame::STUB)); |
+ // Adjust FP to point to saved FP. |
+ __ Addu(fp, sp, Operand(2 * kPointerSize)); |
+ } else { |
+ // The following three instructions must remain together and unmodified |
+ // for code aging to work properly. |
+ __ Push(ra, fp, cp, a1); |
+ // Add unused load of ip to ensure prologue sequence is identical for |
+ // full-codegen and lithium-codegen. |
+ __ LoadRoot(at, Heap::kUndefinedValueRootIndex); |
+ // Adj. FP to point to saved FP. |
+ __ Addu(fp, sp, Operand(2 * kPointerSize)); |
+ } |
frame_is_built_ = true; |
} |
@@ -162,18 +169,37 @@ bool LCodeGen::GeneratePrologue() { |
int slots = GetStackSlotCount(); |
if (slots > 0) { |
if (FLAG_debug_code) { |
- __ li(a0, Operand(slots)); |
- __ li(a2, Operand(kSlotsZapValue)); |
+ __ Subu(sp, sp, Operand(slots * kPointerSize)); |
+ __ push(a0); |
+ __ push(a1); |
+ __ Addu(a0, sp, Operand(slots * kPointerSize)); |
+ __ li(a1, Operand(kSlotsZapValue)); |
Label loop; |
__ bind(&loop); |
- __ push(a2); |
- __ Subu(a0, a0, 1); |
- __ Branch(&loop, ne, a0, Operand(zero_reg)); |
+ __ Subu(a0, a0, Operand(kPointerSize)); |
+ __ sw(a1, MemOperand(a0, 2 * kPointerSize)); |
+ __ Branch(&loop, ne, a0, Operand(sp)); |
+ __ pop(a1); |
+ __ pop(a0); |
} else { |
__ Subu(sp, sp, Operand(slots * kPointerSize)); |
} |
} |
+ if (info()->saves_caller_doubles() && CpuFeatures::IsSupported(FPU)) { |
+ CpuFeatures::Scope scope(FPU); |
+ Comment(";;; Save clobbered callee double registers"); |
+ int count = 0; |
+ BitVector* doubles = chunk()->allocated_double_registers(); |
+ BitVector::Iterator save_iterator(doubles); |
+ while (!save_iterator.Done()) { |
+ __ sdc1(DoubleRegister::FromAllocationIndex(save_iterator.Current()), |
+ MemOperand(sp, count * kDoubleSize)); |
+ save_iterator.Advance(); |
+ count++; |
+ } |
+ } |
+ |
// Possibly allocate a local context. |
int heap_slots = info()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS; |
if (heap_slots > 0) { |
@@ -2461,11 +2487,26 @@ void LCodeGen::DoReturn(LReturn* instr) { |
__ push(v0); |
__ CallRuntime(Runtime::kTraceExit, 1); |
} |
+ if (info()->saves_caller_doubles() && CpuFeatures::IsSupported(FPU)) { |
+ CpuFeatures::Scope scope(FPU); |
+ ASSERT(NeedsEagerFrame()); |
+ BitVector* doubles = chunk()->allocated_double_registers(); |
+ BitVector::Iterator save_iterator(doubles); |
+ int count = 0; |
+ while (!save_iterator.Done()) { |
+ __ ldc1(DoubleRegister::FromAllocationIndex(save_iterator.Current()), |
+ MemOperand(sp, count * kDoubleSize)); |
+ save_iterator.Advance(); |
+ count++; |
+ } |
+ } |
if (NeedsEagerFrame()) { |
int32_t sp_delta = (GetParameterCount() + 1) * kPointerSize; |
__ mov(sp, fp); |
__ Pop(ra, fp); |
- __ Addu(sp, sp, Operand(sp_delta)); |
+ if (!info()->IsStub()) { |
+ __ Addu(sp, sp, Operand(sp_delta)); |
+ } |
} |
__ Jump(ra); |
} |
@@ -3242,8 +3283,14 @@ void LCodeGen::DoThisFunction(LThisFunction* instr) { |
void LCodeGen::DoContext(LContext* instr) { |
+ // If there is a non-return use, the context must be moved to a register. |
Register result = ToRegister(instr->result()); |
- __ mov(result, cp); |
+ for (HUseIterator it(instr->hydrogen()->uses()); !it.Done(); it.Advance()) { |
+ if (!it.value()->IsReturn()) { |
+ __ mov(result, cp); |
+ return; |
+ } |
+ } |
} |
@@ -4190,7 +4237,6 @@ void LCodeGen::DoStoreKeyedGeneric(LStoreKeyedGeneric* instr) { |
void LCodeGen::DoTransitionElementsKind(LTransitionElementsKind* instr) { |
Register object_reg = ToRegister(instr->object()); |
- Register new_map_reg = ToRegister(instr->new_map_temp()); |
Register scratch = scratch0(); |
Handle<Map> from_map = instr->original_map(); |
@@ -4198,23 +4244,32 @@ void LCodeGen::DoTransitionElementsKind(LTransitionElementsKind* instr) { |
ElementsKind from_kind = instr->from_kind(); |
ElementsKind to_kind = instr->to_kind(); |
- __ mov(ToRegister(instr->result()), object_reg); |
- |
Label not_applicable; |
__ lw(scratch, FieldMemOperand(object_reg, HeapObject::kMapOffset)); |
__ Branch(¬_applicable, ne, scratch, Operand(from_map)); |
- __ li(new_map_reg, Operand(to_map)); |
if (IsSimpleMapChangeTransition(from_kind, to_kind)) { |
+ Register new_map_reg = ToRegister(instr->new_map_temp()); |
+ __ li(new_map_reg, Operand(to_map)); |
__ sw(new_map_reg, FieldMemOperand(object_reg, HeapObject::kMapOffset)); |
// Write barrier. |
__ RecordWriteField(object_reg, HeapObject::kMapOffset, new_map_reg, |
scratch, kRAHasBeenSaved, kDontSaveFPRegs); |
+ } else if (FLAG_compiled_transitions) { |
+ PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters); |
+ __ mov(a0, object_reg); |
+ __ li(a1, Operand(to_map)); |
+ TransitionElementsKindStub stub(from_kind, to_kind); |
+ __ CallStub(&stub); |
+ RecordSafepointWithRegisters( |
+ instr->pointer_map(), 0, Safepoint::kNoLazyDeopt); |
} else if (IsFastSmiElementsKind(from_kind) && |
IsFastDoubleElementsKind(to_kind)) { |
Register fixed_object_reg = ToRegister(instr->temp()); |
ASSERT(fixed_object_reg.is(a2)); |
+ Register new_map_reg = ToRegister(instr->new_map_temp()); |
ASSERT(new_map_reg.is(a3)); |
+ __ li(new_map_reg, Operand(to_map)); |
__ mov(fixed_object_reg, object_reg); |
CallCode(isolate()->builtins()->TransitionElementsSmiToDouble(), |
RelocInfo::CODE_TARGET, instr); |
@@ -4222,7 +4277,9 @@ void LCodeGen::DoTransitionElementsKind(LTransitionElementsKind* instr) { |
IsFastObjectElementsKind(to_kind)) { |
Register fixed_object_reg = ToRegister(instr->temp()); |
ASSERT(fixed_object_reg.is(a2)); |
+ Register new_map_reg = ToRegister(instr->new_map_temp()); |
ASSERT(new_map_reg.is(a3)); |
+ __ li(new_map_reg, Operand(to_map)); |
__ mov(fixed_object_reg, object_reg); |
CallCode(isolate()->builtins()->TransitionElementsDoubleToObject(), |
RelocInfo::CODE_TARGET, instr); |
@@ -4233,6 +4290,16 @@ void LCodeGen::DoTransitionElementsKind(LTransitionElementsKind* instr) { |
} |
+void LCodeGen::DoTrapAllocationMemento(LTrapAllocationMemento* instr) { |
+ Register object = ToRegister(instr->object()); |
+ Register temp = ToRegister(instr->temp()); |
+ Label fail; |
+ __ TestJSArrayForAllocationSiteInfo(object, temp, ne, &fail); |
+ DeoptimizeIf(al, instr->environment()); |
+ __ bind(&fail); |
+} |
+ |
+ |
void LCodeGen::DoStringAdd(LStringAdd* instr) { |
__ push(ToRegister(instr->left())); |
__ push(ToRegister(instr->right())); |
@@ -4569,6 +4636,52 @@ void LCodeGen::DoNumberTagD(LNumberTagD* instr) { |
Register temp1 = ToRegister(instr->temp()); |
Register temp2 = ToRegister(instr->temp2()); |
+ bool convert_hole = false; |
+ HValue* change_input = instr->hydrogen()->value(); |
+ if (change_input->IsLoadKeyed()) { |
+ HLoadKeyed* load = HLoadKeyed::cast(change_input); |
+ convert_hole = load->UsesMustHandleHole(); |
+ } |
+ |
+ Label no_special_nan_handling; |
+ Label done; |
+ if (convert_hole) { |
+ if (CpuFeatures::IsSupported(FPU)) { |
+ CpuFeatures::Scope scope(FPU); |
+ DoubleRegister input_reg = ToDoubleRegister(instr->value()); |
+ __ BranchF(&no_special_nan_handling, NULL, eq, input_reg, input_reg); |
+ __ Move(reg, scratch0(), input_reg); |
+ Label canonicalize; |
+ __ Branch(&canonicalize, ne, scratch0(), Operand(kHoleNanUpper32)); |
+ __ li(reg, factory()->the_hole_value()); |
+ __ Branch(&done); |
+ __ bind(&canonicalize); |
+ __ Move(input_reg, |
+ FixedDoubleArray::canonical_not_the_hole_nan_as_double()); |
+ } else { |
+ Label not_hole; |
+ __ Branch(¬_hole, ne, sfpd_hi, Operand(kHoleNanUpper32)); |
+ __ li(reg, factory()->the_hole_value()); |
+ __ Branch(&done); |
+ __ bind(¬_hole); |
+ __ And(scratch, sfpd_hi, Operand(0x7ff00000)); |
+ __ Branch(&no_special_nan_handling, ne, scratch, Operand(0x7ff00000)); |
+ Label special_nan_handling; |
+ __ And(at, sfpd_hi, Operand(0x000FFFFF)); |
+ __ Branch(&special_nan_handling, ne, at, Operand(zero_reg)); |
+ __ Branch(&no_special_nan_handling, eq, sfpd_lo, Operand(zero_reg)); |
+ __ bind(&special_nan_handling); |
+ double canonical_nan = |
+ FixedDoubleArray::canonical_not_the_hole_nan_as_double(); |
+ uint64_t casted_nan = BitCast<uint64_t>(canonical_nan); |
+ __ li(sfpd_lo, |
+ Operand(static_cast<uint32_t>(casted_nan & 0xFFFFFFFF))); |
+ __ li(sfpd_hi, |
+ Operand(static_cast<uint32_t>(casted_nan >> 32))); |
+ } |
+ } |
+ |
+ __ bind(&no_special_nan_handling); |
DeferredNumberTagD* deferred = new(zone()) DeferredNumberTagD(this, instr); |
if (FLAG_inline_new) { |
__ LoadRoot(scratch, Heap::kHeapNumberMapRootIndex); |
@@ -4588,6 +4701,7 @@ void LCodeGen::DoNumberTagD(LNumberTagD* instr) { |
} |
// Now that we have finished with the object's real address tag it |
__ Addu(reg, reg, kHeapObjectTag); |
+ __ bind(&done); |
} |
@@ -4631,43 +4745,57 @@ void LCodeGen::EmitNumberUntagD(Register input_reg, |
DoubleRegister result_reg, |
bool deoptimize_on_undefined, |
bool deoptimize_on_minus_zero, |
- LEnvironment* env) { |
+ LEnvironment* env, |
+ NumberUntagDMode mode) { |
Register scratch = scratch0(); |
CpuFeatures::Scope scope(FPU); |
Label load_smi, heap_number, done; |
- // Smi check. |
- __ UntagAndJumpIfSmi(scratch, input_reg, &load_smi); |
+ if (mode == NUMBER_CANDIDATE_IS_ANY_TAGGED) { |
+ // Smi check. |
+ __ UntagAndJumpIfSmi(scratch, input_reg, &load_smi); |
- // Heap number map check. |
- __ lw(scratch, FieldMemOperand(input_reg, HeapObject::kMapOffset)); |
- __ LoadRoot(at, Heap::kHeapNumberMapRootIndex); |
- if (deoptimize_on_undefined) { |
- DeoptimizeIf(ne, env, scratch, Operand(at)); |
- } else { |
- Label heap_number; |
- __ Branch(&heap_number, eq, scratch, Operand(at)); |
+ // Heap number map check. |
+ __ lw(scratch, FieldMemOperand(input_reg, HeapObject::kMapOffset)); |
+ __ LoadRoot(at, Heap::kHeapNumberMapRootIndex); |
+ if (deoptimize_on_undefined) { |
+ DeoptimizeIf(ne, env, scratch, Operand(at)); |
+ } else { |
+ Label heap_number; |
+ __ Branch(&heap_number, eq, scratch, Operand(at)); |
- __ LoadRoot(at, Heap::kUndefinedValueRootIndex); |
- DeoptimizeIf(ne, env, input_reg, Operand(at)); |
+ __ LoadRoot(at, Heap::kUndefinedValueRootIndex); |
+ DeoptimizeIf(ne, env, input_reg, Operand(at)); |
- // Convert undefined to NaN. |
- __ LoadRoot(at, Heap::kNanValueRootIndex); |
- __ ldc1(result_reg, FieldMemOperand(at, HeapNumber::kValueOffset)); |
- __ Branch(&done); |
+ // Convert undefined to NaN. |
+ __ LoadRoot(at, Heap::kNanValueRootIndex); |
+ __ ldc1(result_reg, FieldMemOperand(at, HeapNumber::kValueOffset)); |
+ __ Branch(&done); |
- __ bind(&heap_number); |
- } |
- // Heap number to double register conversion. |
- __ ldc1(result_reg, FieldMemOperand(input_reg, HeapNumber::kValueOffset)); |
- if (deoptimize_on_minus_zero) { |
- __ mfc1(at, result_reg.low()); |
- __ Branch(&done, ne, at, Operand(zero_reg)); |
- __ mfc1(scratch, result_reg.high()); |
- DeoptimizeIf(eq, env, scratch, Operand(HeapNumber::kSignMask)); |
+ __ bind(&heap_number); |
+ } |
+ // Heap number to double register conversion. |
+ __ ldc1(result_reg, FieldMemOperand(input_reg, HeapNumber::kValueOffset)); |
+ if (deoptimize_on_minus_zero) { |
+ __ mfc1(at, result_reg.low()); |
+ __ Branch(&done, ne, at, Operand(zero_reg)); |
+ __ mfc1(scratch, result_reg.high()); |
+ DeoptimizeIf(eq, env, scratch, Operand(HeapNumber::kSignMask)); |
+ } |
+ __ Branch(&done); |
+ } else if (mode == NUMBER_CANDIDATE_IS_SMI_OR_HOLE) { |
+ __ SmiUntag(scratch, input_reg); |
+ DeoptimizeIf(Ugreater_equal, env, scratch, Operand(zero_reg)); |
+ } else if (mode == NUMBER_CANDIDATE_IS_SMI_CONVERT_HOLE) { |
+ __ UntagAndJumpIfSmi(scratch, input_reg, &load_smi); |
+ __ Move(result_reg, |
+ FixedDoubleArray::hole_nan_as_double()); |
+ __ Branch(&done); |
+ } else { |
+ __ SmiUntag(scratch, input_reg); |
+ ASSERT(mode == NUMBER_CANDIDATE_IS_SMI); |
} |
- __ Branch(&done); |
// Smi to double register conversion |
__ bind(&load_smi); |
@@ -4794,10 +4922,28 @@ void LCodeGen::DoNumberUntagD(LNumberUntagD* instr) { |
Register input_reg = ToRegister(input); |
DoubleRegister result_reg = ToDoubleRegister(result); |
+ NumberUntagDMode mode = NUMBER_CANDIDATE_IS_ANY_TAGGED; |
+ HValue* value = instr->hydrogen()->value(); |
+ if (value->type().IsSmi()) { |
+ if (value->IsLoadKeyed()) { |
+ HLoadKeyed* load = HLoadKeyed::cast(value); |
+ if (load->UsesMustHandleHole()) { |
+ if (load->hole_mode() == ALLOW_RETURN_HOLE) { |
+ mode = NUMBER_CANDIDATE_IS_SMI_CONVERT_HOLE; |
+ } else { |
+ mode = NUMBER_CANDIDATE_IS_SMI_OR_HOLE; |
+ } |
+ } else { |
+ mode = NUMBER_CANDIDATE_IS_SMI; |
+ } |
+ } |
+ } |
+ |
EmitNumberUntagD(input_reg, result_reg, |
instr->hydrogen()->deoptimize_on_undefined(), |
instr->hydrogen()->deoptimize_on_minus_zero(), |
- instr->environment()); |
+ instr->environment(), |
+ mode); |
} |
@@ -5091,6 +5237,63 @@ void LCodeGen::DoDeferredAllocateObject(LAllocateObject* instr) { |
} |
+void LCodeGen::DoAllocate(LAllocate* instr) { |
+ class DeferredAllocate: public LDeferredCode { |
+ public: |
+ DeferredAllocate(LCodeGen* codegen, LAllocate* instr) |
+ : LDeferredCode(codegen), instr_(instr) { } |
+ virtual void Generate() { codegen()->DoDeferredAllocate(instr_); } |
+ virtual LInstruction* instr() { return instr_; } |
+ private: |
+ LAllocate* instr_; |
+ }; |
+ |
+ DeferredAllocate* deferred = |
+ new(zone()) DeferredAllocate(this, instr); |
+ |
+ Register size = ToRegister(instr->size()); |
+ Register result = ToRegister(instr->result()); |
+ Register scratch = ToRegister(instr->temp1()); |
+ Register scratch2 = ToRegister(instr->temp2()); |
+ |
+ HAllocate* original_instr = instr->hydrogen(); |
+ if (original_instr->size()->IsConstant()) { |
+ UNREACHABLE(); |
+ } else { |
+ // Allocate memory for the object. |
+ AllocationFlags flags = TAG_OBJECT; |
+ if (original_instr->MustAllocateDoubleAligned()) { |
+ flags = static_cast<AllocationFlags>(flags | DOUBLE_ALIGNMENT); |
+ } |
+ __ AllocateInNewSpace(size, |
+ result, |
+ scratch, |
+ scratch2, |
+ deferred->entry(), |
+ TAG_OBJECT); |
+ } |
+ |
+ __ bind(deferred->exit()); |
+} |
+ |
+ |
+void LCodeGen::DoDeferredAllocate(LAllocate* instr) { |
+ Register size = ToRegister(instr->size()); |
+ Register result = ToRegister(instr->result()); |
+ |
+ // TODO(3095996): Get rid of this. For now, we need to make the |
+ // result register contain a valid pointer because it is already |
+ // contained in the register pointer map. |
+ __ mov(result, zero_reg); |
+ |
+ PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters); |
+ __ SmiTag(size, size); |
+ __ push(size); |
+ CallRuntimeFromDeferred(Runtime::kAllocateInNewSpace, 1, instr); |
+ __ StoreToSafepointRegisterSlot(v0, result); |
+} |
+ |
+ |
void LCodeGen::DoArrayLiteral(LArrayLiteral* instr) { |
Handle<FixedArray> literals(instr->environment()->closure()->literals()); |
ElementsKind boilerplate_elements_kind = |