X87: enable the crankshaft compiler for X87 port.
authorweiliang.lin@intel.com <weiliang.lin@intel.com>
Sat, 20 Sep 2014 05:08:58 +0000 (05:08 +0000)
committerweiliang.lin@intel.com <weiliang.lin@intel.com>
Sat, 20 Sep 2014 05:08:58 +0000 (05:08 +0000)
BUG=
R=weiliang.lin@intel.com

Review URL: https://codereview.chromium.org/579713002

Patch from Chunyang Dai <chunyang.dai@intel.com>.

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@24102 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

20 files changed:
src/ic/x87/handler-compiler-x87.cc
src/ic/x87/ic-x87.cc
src/x87/assembler-x87-inl.h
src/x87/assembler-x87.cc
src/x87/assembler-x87.h
src/x87/builtins-x87.cc
src/x87/code-stubs-x87.cc
src/x87/code-stubs-x87.h
src/x87/codegen-x87.cc
src/x87/deoptimizer-x87.cc
src/x87/disasm-x87.cc
src/x87/full-codegen-x87.cc
src/x87/lithium-codegen-x87.cc
src/x87/lithium-codegen-x87.h
src/x87/lithium-gap-resolver-x87.cc
src/x87/lithium-x87.cc
src/x87/lithium-x87.h
src/x87/macro-assembler-x87.cc
src/x87/macro-assembler-x87.h
test/cctest/test-disasm-x87.cc

index 8370f68..e706998 100644 (file)
@@ -411,7 +411,7 @@ void NamedStoreHandlerCompiler::GenerateStoreTransition(
 
   // Update the write barrier for the map field.
   __ RecordWriteField(receiver_reg, HeapObject::kMapOffset, scratch1, scratch2,
-                      OMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
+                      kDontSaveFPRegs, OMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
 
   if (details.type() == CONSTANT) {
     DCHECK(value_reg.is(eax));
@@ -445,7 +445,7 @@ void NamedStoreHandlerCompiler::GenerateStoreTransition(
         __ mov(storage_reg, value_reg);
       }
       __ RecordWriteField(receiver_reg, offset, storage_reg, scratch1,
-                          EMIT_REMEMBERED_SET, smi_check);
+                          kDontSaveFPRegs, EMIT_REMEMBERED_SET, smi_check);
     }
   } else {
     // Write to the properties array.
@@ -464,7 +464,7 @@ void NamedStoreHandlerCompiler::GenerateStoreTransition(
         __ mov(storage_reg, value_reg);
       }
       __ RecordWriteField(scratch1, offset, storage_reg, receiver_reg,
-                          EMIT_REMEMBERED_SET, smi_check);
+                          kDontSaveFPRegs, EMIT_REMEMBERED_SET, smi_check);
     }
   }
 
index 2cd6ea1..499d8da 100644 (file)
@@ -133,7 +133,7 @@ static void GenerateDictionaryStore(MacroAssembler* masm, Label* miss_label,
 
   // Update write barrier. Make sure not to clobber the value.
   __ mov(r1, value);
-  __ RecordWrite(elements, r0, r1);
+  __ RecordWrite(elements, r0, r1, kDontSaveFPRegs);
 }
 
 
@@ -546,7 +546,7 @@ void KeyedStoreIC::GenerateSloppyArguments(MacroAssembler* masm) {
   __ mov(mapped_location, value);
   __ lea(ecx, mapped_location);
   __ mov(edx, value);
-  __ RecordWrite(ebx, ecx, edx);
+  __ RecordWrite(ebx, ecx, edx, kDontSaveFPRegs);
   __ Ret();
   __ bind(&notin);
   // The unmapped lookup expects that the parameter map is in ebx.
@@ -555,7 +555,7 @@ void KeyedStoreIC::GenerateSloppyArguments(MacroAssembler* masm) {
   __ mov(unmapped_location, value);
   __ lea(edi, unmapped_location);
   __ mov(edx, value);
-  __ RecordWrite(ebx, edi, edx);
+  __ RecordWrite(ebx, edi, edx, kDontSaveFPRegs);
   __ Ret();
   __ bind(&slow);
   GenerateMiss(masm);
@@ -624,7 +624,8 @@ static void KeyedStoreGenerateGenericHelper(
   __ mov(FixedArrayElementOperand(ebx, key), value);
   // Update write barrier for the elements array address.
   __ mov(edx, value);  // Preserve the value which is returned.
-  __ RecordWriteArray(ebx, edx, key, EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
+  __ RecordWriteArray(ebx, edx, key, kDontSaveFPRegs, EMIT_REMEMBERED_SET,
+                      OMIT_SMI_CHECK);
   __ ret(0);
 
   __ bind(fast_double);
index 25ecfcf..6555ccd 100644 (file)
@@ -45,7 +45,7 @@
 namespace v8 {
 namespace internal {
 
-bool CpuFeatures::SupportsCrankshaft() { return false; }
+bool CpuFeatures::SupportsCrankshaft() { return true; }
 
 
 static const byte kCallOpcode = 0xE8;
index 8f92249..9e1c883 100644 (file)
@@ -1519,6 +1519,20 @@ void Assembler::fst_s(const Operand& adr) {
 }
 
 
+void Assembler::fldcw(const Operand& adr) {
+  EnsureSpace ensure_space(this);
+  EMIT(0xD9);
+  emit_operand(ebp, adr);
+}
+
+
+void Assembler::fnstcw(const Operand& adr) {
+  EnsureSpace ensure_space(this);
+  EMIT(0xD9);
+  emit_operand(edi, adr);
+}
+
+
 void Assembler::fstp_d(const Operand& adr) {
   EnsureSpace ensure_space(this);
   EMIT(0xDD);
@@ -1598,6 +1612,13 @@ void Assembler::fchs() {
 }
 
 
+void Assembler::fsqrt() {
+  EnsureSpace ensure_space(this);
+  EMIT(0xD9);
+  EMIT(0xFA);
+}
+
+
 void Assembler::fcos() {
   EnsureSpace ensure_space(this);
   EMIT(0xD9);
@@ -1659,6 +1680,13 @@ void Assembler::fadd_i(int i) {
 }
 
 
+void Assembler::fadd_d(const Operand& adr) {
+  EnsureSpace ensure_space(this);
+  EMIT(0xDC);
+  emit_operand(eax, adr);
+}
+
+
 void Assembler::fsub(int i) {
   EnsureSpace ensure_space(this);
   emit_farith(0xDC, 0xE8, i);
@@ -1772,6 +1800,13 @@ void Assembler::ftst() {
 }
 
 
+void Assembler::fxam() {
+  EnsureSpace ensure_space(this);
+  EMIT(0xD9);
+  EMIT(0xE5);
+}
+
+
 void Assembler::fucomp(int i) {
   EnsureSpace ensure_space(this);
   emit_farith(0xDD, 0xE8, i);
@@ -1833,6 +1868,20 @@ void Assembler::fnclex() {
 }
 
 
+void Assembler::fnsave(const Operand& adr) {
+  EnsureSpace ensure_space(this);
+  EMIT(0xDD);
+  emit_operand(esi, adr);
+}
+
+
+void Assembler::frstor(const Operand& adr) {
+  EnsureSpace ensure_space(this);
+  EMIT(0xDD);
+  emit_operand(esp, adr);
+}
+
+
 void Assembler::sahf() {
   EnsureSpace ensure_space(this);
   EMIT(0x9E);
index a2bedcc..d37c9d7 100644 (file)
@@ -142,7 +142,7 @@ inline Register Register::FromAllocationIndex(int index)  {
 
 
 struct X87Register {
-  static const int kMaxNumAllocatableRegisters = 8;
+  static const int kMaxNumAllocatableRegisters = 6;
   static const int kMaxNumRegisters = 8;
   static int NumAllocatableRegisters() {
     return kMaxNumAllocatableRegisters;
@@ -852,6 +852,7 @@ class Assembler : public AssemblerBase {
 
   void fabs();
   void fchs();
+  void fsqrt();
   void fcos();
   void fsin();
   void fptan();
@@ -862,6 +863,7 @@ class Assembler : public AssemblerBase {
 
   void fadd(int i);
   void fadd_i(int i);
+  void fadd_d(const Operand& adr);
   void fsub(int i);
   void fsub_i(int i);
   void fmul(int i);
@@ -884,14 +886,19 @@ class Assembler : public AssemblerBase {
   void ffree(int i = 0);
 
   void ftst();
+  void fxam();
   void fucomp(int i);
   void fucompp();
   void fucomi(int i);
   void fucomip();
   void fcompp();
   void fnstsw_ax();
+  void fldcw(const Operand& adr);
+  void fnstcw(const Operand& adr);
   void fwait();
   void fnclex();
+  void fnsave(const Operand& adr);
+  void frstor(const Operand& adr);
 
   void frndint();
 
index 6857cdc..d631175 100644 (file)
@@ -660,7 +660,8 @@ void Builtins::Generate_MarkCodeAsExecutedTwice(MacroAssembler* masm) {
 }
 
 
-static void Generate_NotifyStubFailureHelper(MacroAssembler* masm) {
+static void Generate_NotifyStubFailureHelper(MacroAssembler* masm,
+                                             SaveFPRegsMode save_doubles) {
   // Enter an internal frame.
   {
     FrameScope scope(masm, StackFrame::INTERNAL);
@@ -669,7 +670,7 @@ static void Generate_NotifyStubFailureHelper(MacroAssembler* masm) {
     // stubs that tail call the runtime on deopts passing their parameters in
     // registers.
     __ pushad();
-    __ CallRuntime(Runtime::kNotifyStubFailure, 0);
+    __ CallRuntime(Runtime::kNotifyStubFailure, 0, save_doubles);
     __ popad();
     // Tear down internal frame.
   }
@@ -680,13 +681,12 @@ static void Generate_NotifyStubFailureHelper(MacroAssembler* masm) {
 
 
 void Builtins::Generate_NotifyStubFailure(MacroAssembler* masm) {
-  Generate_NotifyStubFailureHelper(masm);
+  Generate_NotifyStubFailureHelper(masm, kDontSaveFPRegs);
 }
 
 
 void Builtins::Generate_NotifyStubFailureSaveDoubles(MacroAssembler* masm) {
-  // SaveDoubles is meanless for X87, just used by deoptimizer.cc
-  Generate_NotifyStubFailureHelper(masm);
+  Generate_NotifyStubFailureHelper(masm, kSaveFPRegs);
 }
 
 
index 35514c3..215d1a0 100644 (file)
@@ -127,6 +127,11 @@ void StoreBufferOverflowStub::Generate(MacroAssembler* masm) {
   // store the registers in any particular way, but we do have to store and
   // restore them.
   __ pushad();
+  if (save_doubles()) {
+    // Save FPU stat in m108byte.
+    __ sub(esp, Immediate(108));
+    __ fnsave(Operand(esp, 0));
+  }
   const int argument_count = 1;
 
   AllowExternalCallThatCantCauseGC scope(masm);
@@ -136,6 +141,11 @@ void StoreBufferOverflowStub::Generate(MacroAssembler* masm) {
   __ CallCFunction(
       ExternalReference::store_buffer_overflow_function(isolate()),
       argument_count);
+  if (save_doubles()) {
+    // Restore FPU stat in m108byte.
+    __ frstor(Operand(esp, 0));
+    __ add(esp, Immediate(108));
+  }
   __ popad();
   __ ret(0);
 }
@@ -1115,16 +1125,12 @@ void RegExpExecStub::Generate(MacroAssembler* masm) {
   __ mov(eax, Operand(esp, kSubjectOffset));
   __ mov(ecx, eax);
   __ mov(FieldOperand(ebx, RegExpImpl::kLastSubjectOffset), eax);
-  __ RecordWriteField(ebx,
-                      RegExpImpl::kLastSubjectOffset,
-                      eax,
-                      edi);
+  __ RecordWriteField(ebx, RegExpImpl::kLastSubjectOffset, eax, edi,
+                      kDontSaveFPRegs);
   __ mov(eax, ecx);
   __ mov(FieldOperand(ebx, RegExpImpl::kLastInputOffset), eax);
-  __ RecordWriteField(ebx,
-                      RegExpImpl::kLastInputOffset,
-                      eax,
-                      edi);
+  __ RecordWriteField(ebx, RegExpImpl::kLastInputOffset, eax, edi,
+                      kDontSaveFPRegs);
 
   // Get the static offsets vector filled by the native regexp code.
   ExternalReference address_of_static_offsets_vector =
@@ -1618,7 +1624,8 @@ static void GenerateRecordCallTarget(MacroAssembler* masm) {
   __ push(edi);
   __ push(ebx);
   __ push(edx);
-  __ RecordWriteArray(ebx, edi, edx, EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
+  __ RecordWriteArray(ebx, edi, edx, kDontSaveFPRegs, EMIT_REMEMBERED_SET,
+                      OMIT_SMI_CHECK);
   __ pop(edx);
   __ pop(ebx);
   __ pop(edi);
@@ -1989,12 +1996,19 @@ void CodeStub::GenerateStubsAheadOfTime(Isolate* isolate) {
 
 
 void CodeStub::GenerateFPStubs(Isolate* isolate) {
-  // Do nothing.
+  CEntryStub save_doubles(isolate, 1, kSaveFPRegs);
+  // Stubs might already be in the snapshot, detect that and don't regenerate,
+  // which would lead to code stub initialization state being messed up.
+  Code* save_doubles_code;
+  if (!save_doubles.FindCodeInCache(&save_doubles_code)) {
+    save_doubles_code = *(save_doubles.GetCode());
+  }
+  isolate->set_fp_stubs_generated(true);
 }
 
 
 void CEntryStub::GenerateAheadOfTime(Isolate* isolate) {
-  CEntryStub stub(isolate, 1);
+  CEntryStub stub(isolate, 1, kDontSaveFPRegs);
   stub.GetCode();
 }
 
@@ -2010,7 +2024,7 @@ void CEntryStub::Generate(MacroAssembler* masm) {
   ProfileEntryHookStub::MaybeCallEntryHook(masm);
 
   // Enter the exit frame that transitions from JavaScript to C++.
-  __ EnterExitFrame();
+  __ EnterExitFrame(save_doubles());
 
   // ebx: pointer to C function  (C callee-saved)
   // ebp: frame pointer  (restored after C call)
@@ -2066,7 +2080,7 @@ void CEntryStub::Generate(MacroAssembler* masm) {
   }
 
   // Exit the JavaScript to C++ exit frame.
-  __ LeaveExitFrame();
+  __ LeaveExitFrame(save_doubles());
   __ ret(0);
 
   // Handling of exception.
@@ -3545,6 +3559,8 @@ void StoreBufferOverflowStub::GenerateFixedRegStubsAheadOfTime(
     Isolate* isolate) {
   StoreBufferOverflowStub stub(isolate, kDontSaveFPRegs);
   stub.GetCode();
+  StoreBufferOverflowStub stub2(isolate, kSaveFPRegs);
+  stub2.GetCode();
 }
 
 
@@ -3564,7 +3580,7 @@ void RecordWriteStub::Generate(MacroAssembler* masm) {
   __ jmp(&skip_to_incremental_compacting, Label::kFar);
 
   if (remembered_set_action() == EMIT_REMEMBERED_SET) {
-    __ RememberedSetHelper(object(), address(), value(),
+    __ RememberedSetHelper(object(), address(), value(), save_fp_regs_mode(),
                            MacroAssembler::kReturnAtEnd);
   } else {
     __ ret(0);
@@ -3608,7 +3624,7 @@ void RecordWriteStub::GenerateIncremental(MacroAssembler* masm, Mode mode) {
         mode);
     InformIncrementalMarker(masm);
     regs_.Restore(masm);
-    __ RememberedSetHelper(object(), address(), value(),
+    __ RememberedSetHelper(object(), address(), value(), save_fp_regs_mode(),
                            MacroAssembler::kReturnAtEnd);
 
     __ bind(&dont_need_remembered_set);
@@ -3625,7 +3641,7 @@ void RecordWriteStub::GenerateIncremental(MacroAssembler* masm, Mode mode) {
 
 
 void RecordWriteStub::InformIncrementalMarker(MacroAssembler* masm) {
-  regs_.SaveCallerSaveRegisters(masm);
+  regs_.SaveCallerSaveRegisters(masm, save_fp_regs_mode());
   int argument_count = 3;
   __ PrepareCallCFunction(argument_count, regs_.scratch0());
   __ mov(Operand(esp, 0 * kPointerSize), regs_.object());
@@ -3638,7 +3654,7 @@ void RecordWriteStub::InformIncrementalMarker(MacroAssembler* masm) {
       ExternalReference::incremental_marking_record_write_function(isolate()),
       argument_count);
 
-  regs_.RestoreCallerSaveRegisters(masm);
+  regs_.RestoreCallerSaveRegisters(masm, save_fp_regs_mode());
 }
 
 
@@ -3669,7 +3685,7 @@ void RecordWriteStub::CheckNeedsToInformIncrementalMarker(
 
   regs_.Restore(masm);
   if (on_no_need == kUpdateRememberedSetOnNoNeedToInformIncrementalMarker) {
-    __ RememberedSetHelper(object(), address(), value(),
+    __ RememberedSetHelper(object(), address(), value(), save_fp_regs_mode(),
                            MacroAssembler::kReturnAtEnd);
   } else {
     __ ret(0);
@@ -3714,7 +3730,7 @@ void RecordWriteStub::CheckNeedsToInformIncrementalMarker(
 
   regs_.Restore(masm);
   if (on_no_need == kUpdateRememberedSetOnNoNeedToInformIncrementalMarker) {
-    __ RememberedSetHelper(object(), address(), value(),
+    __ RememberedSetHelper(object(), address(), value(), save_fp_regs_mode(),
                            MacroAssembler::kReturnAtEnd);
   } else {
     __ ret(0);
@@ -3784,8 +3800,7 @@ void StoreArrayLiteralElementStub::Generate(MacroAssembler* masm) {
                            FixedArrayBase::kHeaderSize));
   __ mov(Operand(ecx, 0), eax);
   // Update the write barrier for the array store.
-  __ RecordWrite(ebx, ecx, eax,
-                 EMIT_REMEMBERED_SET,
+  __ RecordWrite(ebx, ecx, eax, kDontSaveFPRegs, EMIT_REMEMBERED_SET,
                  OMIT_SMI_CHECK);
   __ ret(0);
 
@@ -3814,7 +3829,7 @@ void StoreArrayLiteralElementStub::Generate(MacroAssembler* masm) {
 
 
 void StubFailureTrampolineStub::Generate(MacroAssembler* masm) {
-  CEntryStub ces(isolate(), 1);
+  CEntryStub ces(isolate(), 1, kSaveFPRegs);
   __ call(ces.GetCode(), RelocInfo::CODE_TARGET);
   int parameter_count_offset =
       StubFailureTrampolineFrame::kCallerStackParameterCountFrameOffset;
index 49462bc..03ff477 100644 (file)
@@ -116,11 +116,9 @@ class NameDictionaryLookupStub: public PlatformCodeStub {
 
 class RecordWriteStub: public PlatformCodeStub {
  public:
-  RecordWriteStub(Isolate* isolate,
-                  Register object,
-                  Register value,
-                  Register address,
-                  RememberedSetAction remembered_set_action)
+  RecordWriteStub(Isolate* isolate, Register object, Register value,
+                  Register address, RememberedSetAction remembered_set_action,
+                  SaveFPRegsMode fp_mode)
       : PlatformCodeStub(isolate),
         regs_(object,   // An input reg.
               address,  // An input reg.
@@ -128,7 +126,8 @@ class RecordWriteStub: public PlatformCodeStub {
     minor_key_ = ObjectBits::encode(object.code()) |
                  ValueBits::encode(value.code()) |
                  AddressBits::encode(address.code()) |
-                 RememberedSetActionBits::encode(remembered_set_action);
+                 RememberedSetActionBits::encode(remembered_set_action) |
+                 SaveFPRegsModeBits::encode(fp_mode);
   }
 
   RecordWriteStub(uint32_t key, Isolate* isolate)
@@ -271,12 +270,23 @@ class RecordWriteStub: public PlatformCodeStub {
     // saved registers that were not already preserved.  The caller saved
     // registers are eax, ecx and edx.  The three scratch registers (incl. ecx)
     // will be restored by other means so we don't bother pushing them here.
-    void SaveCallerSaveRegisters(MacroAssembler* masm) {
+    void SaveCallerSaveRegisters(MacroAssembler* masm, SaveFPRegsMode mode) {
       if (!scratch0_.is(eax) && !scratch1_.is(eax)) masm->push(eax);
       if (!scratch0_.is(edx) && !scratch1_.is(edx)) masm->push(edx);
+      if (mode == kSaveFPRegs) {
+        // Save FPU state in m108byte.
+        masm->sub(esp, Immediate(108));
+        masm->fnsave(Operand(esp, 0));
+      }
     }
 
-    inline void RestoreCallerSaveRegisters(MacroAssembler*masm) {
+    inline void RestoreCallerSaveRegisters(MacroAssembler* masm,
+                                           SaveFPRegsMode mode) {
+      if (mode == kSaveFPRegs) {
+        // Restore FPU state in m108byte.
+        masm->frstor(Operand(esp, 0));
+        masm->add(esp, Immediate(108));
+      }
       if (!scratch0_.is(edx) && !scratch1_.is(edx)) masm->pop(edx);
       if (!scratch0_.is(eax) && !scratch1_.is(eax)) masm->pop(eax);
     }
@@ -348,10 +358,15 @@ class RecordWriteStub: public PlatformCodeStub {
     return RememberedSetActionBits::decode(minor_key_);
   }
 
+  SaveFPRegsMode save_fp_regs_mode() const {
+    return SaveFPRegsModeBits::decode(minor_key_);
+  }
+
   class ObjectBits: public BitField<int, 0, 3> {};
   class ValueBits: public BitField<int, 3, 3> {};
   class AddressBits: public BitField<int, 6, 3> {};
   class RememberedSetActionBits: public BitField<RememberedSetAction, 9, 1> {};
+  class SaveFPRegsModeBits : public BitField<SaveFPRegsMode, 10, 1> {};
 
   RegisterAllocation regs_;
 
index 56d273c..e33959e 100644 (file)
@@ -217,12 +217,8 @@ void ElementsTransitionGenerator::GenerateMapChangeElementsTransition(
 
   // Set transitioned map.
   __ mov(FieldOperand(receiver, HeapObject::kMapOffset), target_map);
-  __ RecordWriteField(receiver,
-                      HeapObject::kMapOffset,
-                      target_map,
-                      scratch,
-                      EMIT_REMEMBERED_SET,
-                      OMIT_SMI_CHECK);
+  __ RecordWriteField(receiver, HeapObject::kMapOffset, target_map, scratch,
+                      kDontSaveFPRegs, EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
 }
 
 
@@ -275,12 +271,8 @@ void ElementsTransitionGenerator::GenerateSmiToDouble(
   // Replace receiver's backing store with newly created FixedDoubleArray.
   __ mov(FieldOperand(edx, JSObject::kElementsOffset), eax);
   __ mov(ebx, eax);
-  __ RecordWriteField(edx,
-                      JSObject::kElementsOffset,
-                      ebx,
-                      edi,
-                      EMIT_REMEMBERED_SET,
-                      OMIT_SMI_CHECK);
+  __ RecordWriteField(edx, JSObject::kElementsOffset, ebx, edi, kDontSaveFPRegs,
+                      EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
 
   __ mov(edi, FieldOperand(esi, FixedArray::kLengthOffset));
 
@@ -339,12 +331,8 @@ void ElementsTransitionGenerator::GenerateSmiToDouble(
   // ebx: target map
   // Set transitioned map.
   __ mov(FieldOperand(edx, HeapObject::kMapOffset), ebx);
-  __ RecordWriteField(edx,
-                      HeapObject::kMapOffset,
-                      ebx,
-                      edi,
-                      OMIT_REMEMBERED_SET,
-                      OMIT_SMI_CHECK);
+  __ RecordWriteField(edx, HeapObject::kMapOffset, ebx, edi, kDontSaveFPRegs,
+                      OMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
 }
 
 
@@ -399,12 +387,8 @@ void ElementsTransitionGenerator::GenerateDoubleToObject(
   // Set transitioned map.
   __ bind(&only_change_map);
   __ mov(FieldOperand(edx, HeapObject::kMapOffset), ebx);
-  __ RecordWriteField(edx,
-                      HeapObject::kMapOffset,
-                      ebx,
-                      edi,
-                      OMIT_REMEMBERED_SET,
-                      OMIT_SMI_CHECK);
+  __ RecordWriteField(edx, HeapObject::kMapOffset, ebx, edi, kDontSaveFPRegs,
+                      OMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
   __ jmp(&success);
 
   // Call into runtime if GC is required.
@@ -433,10 +417,7 @@ void ElementsTransitionGenerator::GenerateDoubleToObject(
   __ mov(FieldOperand(edx, HeapNumber::kValueOffset + kPointerSize), esi);
   __ mov(FieldOperand(eax, ebx, times_2, FixedArray::kHeaderSize), edx);
   __ mov(esi, ebx);
-  __ RecordWriteArray(eax,
-                      edx,
-                      esi,
-                      EMIT_REMEMBERED_SET,
+  __ RecordWriteArray(eax, edx, esi, kDontSaveFPRegs, EMIT_REMEMBERED_SET,
                       OMIT_SMI_CHECK);
   __ jmp(&entry, Label::kNear);
 
@@ -455,20 +436,12 @@ void ElementsTransitionGenerator::GenerateDoubleToObject(
   // edx: receiver
   // Set transitioned map.
   __ mov(FieldOperand(edx, HeapObject::kMapOffset), ebx);
-  __ RecordWriteField(edx,
-                      HeapObject::kMapOffset,
-                      ebx,
-                      edi,
-                      OMIT_REMEMBERED_SET,
-                      OMIT_SMI_CHECK);
+  __ RecordWriteField(edx, HeapObject::kMapOffset, ebx, edi, kDontSaveFPRegs,
+                      OMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
   // Replace receiver's backing store with newly created and filled FixedArray.
   __ mov(FieldOperand(edx, JSObject::kElementsOffset), eax);
-  __ RecordWriteField(edx,
-                      JSObject::kElementsOffset,
-                      eax,
-                      edi,
-                      EMIT_REMEMBERED_SET,
-                      OMIT_SMI_CHECK);
+  __ RecordWriteField(edx, JSObject::kElementsOffset, eax, edi, kDontSaveFPRegs,
+                      EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
 
   // Restore registers.
   __ pop(eax);
index e873ac5..a76c7a7 100644 (file)
@@ -204,8 +204,10 @@ void Deoptimizer::SetPlatformCompiledStubRegisters(
 
 
 void Deoptimizer::CopyDoubleRegisters(FrameDescription* output_frame) {
-  // Do nothing for X87.
-  return;
+  for (int i = 0; i < X87Register::kMaxNumAllocatableRegisters; ++i) {
+    double double_value = input_->GetDoubleRegister(i);
+    output_frame->SetDoubleRegister(i, double_value);
+  }
 }
 
 
@@ -230,9 +232,42 @@ void Deoptimizer::EntryGenerator::Generate() {
 
   // Save all general purpose registers before messing with them.
   const int kNumberOfRegisters = Register::kNumRegisters;
+
+  const int kDoubleRegsSize =
+      kDoubleSize * X87Register::kMaxNumAllocatableRegisters;
+
+  // Reserve space for x87 fp registers.
+  __ sub(esp, Immediate(kDoubleRegsSize));
+
   __ pushad();
 
-  const int kSavedRegistersAreaSize = kNumberOfRegisters * kPointerSize;
+  // GP registers are safe to use now.
+  // Save used x87 fp registers in correct position of previous reserve space.
+  Label loop, done;
+  // Get the layout of x87 stack.
+  __ sub(esp, Immediate(kPointerSize));
+  __ fistp_s(MemOperand(esp, 0));
+  __ pop(eax);
+  // Preserve stack layout in edi
+  __ mov(edi, eax);
+  // Get the x87 stack depth, the first 3 bits.
+  __ mov(ecx, eax);
+  __ and_(ecx, 0x7);
+  __ j(zero, &done, Label::kNear);
+
+  __ bind(&loop);
+  __ shr(eax, 0x3);
+  __ mov(ebx, eax);
+  __ and_(ebx, 0x7);  // Extract the st_x index into ebx.
+  // Pop TOS to the correct position. The disp(0x20) is due to pushad.
+  // The st_i should be saved to (esp + ebx * kDoubleSize + 0x20).
+  __ fstp_d(Operand(esp, ebx, times_8, 0x20));
+  __ dec(ecx);  // Decrease stack depth.
+  __ j(not_zero, &loop, Label::kNear);
+  __ bind(&done);
+
+  const int kSavedRegistersAreaSize =
+      kNumberOfRegisters * kPointerSize + kDoubleRegsSize;
 
   // Get the bailout id from the stack.
   __ mov(ebx, Operand(esp, kSavedRegistersAreaSize));
@@ -245,6 +280,7 @@ void Deoptimizer::EntryGenerator::Generate() {
   __ sub(edx, ebp);
   __ neg(edx);
 
+  __ push(edi);
   // Allocate a new deoptimizer object.
   __ PrepareCallCFunction(6, eax);
   __ mov(eax, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
@@ -260,6 +296,8 @@ void Deoptimizer::EntryGenerator::Generate() {
     __ CallCFunction(ExternalReference::new_deoptimizer_function(isolate()), 6);
   }
 
+  __ pop(edi);
+
   // Preserve deoptimizer object in register eax and get the input
   // frame descriptor pointer.
   __ mov(ebx, Operand(eax, Deoptimizer::input_offset()));
@@ -270,13 +308,22 @@ void Deoptimizer::EntryGenerator::Generate() {
     __ pop(Operand(ebx, offset));
   }
 
+  int double_regs_offset = FrameDescription::double_registers_offset();
+  // Fill in the double input registers.
+  for (int i = 0; i < X87Register::kMaxNumAllocatableRegisters; ++i) {
+    int dst_offset = i * kDoubleSize + double_regs_offset;
+    int src_offset = i * kDoubleSize;
+    __ fld_d(Operand(esp, src_offset));
+    __ fstp_d(Operand(ebx, dst_offset));
+  }
+
   // Clear FPU all exceptions.
   // TODO(ulan): Find out why the TOP register is not zero here in some cases,
   // and check that the generated code never deoptimizes with unbalanced stack.
   __ fnclex();
 
   // Remove the bailout id, return address and the double registers.
-  __ add(esp, Immediate(2 * kPointerSize));
+  __ add(esp, Immediate(kDoubleRegsSize + 2 * kPointerSize));
 
   // Compute a pointer to the unwinding limit in register ecx; that is
   // the first stack slot not part of the input frame.
@@ -298,6 +345,7 @@ void Deoptimizer::EntryGenerator::Generate() {
   __ j(not_equal, &pop_loop);
 
   // Compute the output frame in the deoptimizer.
+  __ push(edi);
   __ push(eax);
   __ PrepareCallCFunction(1, ebx);
   __ mov(Operand(esp, 0 * kPointerSize), eax);
@@ -307,6 +355,7 @@ void Deoptimizer::EntryGenerator::Generate() {
         ExternalReference::compute_output_frames_function(isolate()), 1);
   }
   __ pop(eax);
+  __ pop(edi);
 
   // If frame was dynamically aligned, pop padding.
   Label no_padding;
@@ -345,6 +394,25 @@ void Deoptimizer::EntryGenerator::Generate() {
   __ cmp(eax, edx);
   __ j(below, &outer_push_loop);
 
+
+  // In case of a failed STUB, we have to restore the x87 stack.
+  // x87 stack layout is in edi.
+  Label loop2, done2;
+  // Get the x87 stack depth, the first 3 bits.
+  __ mov(ecx, edi);
+  __ and_(ecx, 0x7);
+  __ j(zero, &done2, Label::kNear);
+
+  __ lea(ecx, Operand(ecx, ecx, times_2, 0));
+  __ bind(&loop2);
+  __ mov(eax, edi);
+  __ shr_cl(eax);
+  __ and_(eax, 0x7);
+  __ fld_d(Operand(ebx, eax, times_8, double_regs_offset));
+  __ sub(ecx, Immediate(0x3));
+  __ j(not_zero, &loop2, Label::kNear);
+  __ bind(&done2);
+
   // Push state, pc, and continuation from the last output frame.
   __ push(Operand(ebx, FrameDescription::state_offset()));
   __ push(Operand(ebx, FrameDescription::pc_offset()));
index 53a8c29..908e8b0 100644 (file)
@@ -702,7 +702,12 @@ int DisassemblerX87::MemoryFPUInstruction(int escape_opcode,
         case 0: mnem = "fld_s"; break;
         case 2: mnem = "fst_s"; break;
         case 3: mnem = "fstp_s"; break;
-        case 7: mnem = "fstcw"; break;
+        case 5:
+          mnem = "fldcw";
+          break;
+        case 7:
+          mnem = "fnstcw";
+          break;
         default: UnimplementedInstruction();
       }
       break;
@@ -716,11 +721,27 @@ int DisassemblerX87::MemoryFPUInstruction(int escape_opcode,
       }
       break;
 
+    case 0xDC:
+      switch (regop) {
+        case 0:
+          mnem = "fadd_d";
+          break;
+        default:
+          UnimplementedInstruction();
+      }
+      break;
+
     case 0xDD: switch (regop) {
         case 0: mnem = "fld_d"; break;
         case 1: mnem = "fisttp_d"; break;
         case 2: mnem = "fst_d"; break;
         case 3: mnem = "fstp_d"; break;
+        case 4:
+          mnem = "frstor";
+          break;
+        case 6:
+          mnem = "fnsave";
+          break;
         default: UnimplementedInstruction();
       }
       break;
index 94ccbcf..58328e0 100644 (file)
@@ -221,10 +221,8 @@ void FullCodeGenerator::Generate() {
         __ mov(Operand(esi, context_offset), eax);
         // Update the write barrier. This clobbers eax and ebx.
         if (need_write_barrier) {
-          __ RecordWriteContextSlot(esi,
-                                    context_offset,
-                                    eax,
-                                    ebx);
+          __ RecordWriteContextSlot(esi, context_offset, eax, ebx,
+                                    kDontSaveFPRegs);
         } else if (FLAG_debug_code) {
           Label done;
           __ JumpIfInNewSpace(esi, eax, &done, Label::kNear);
@@ -708,7 +706,7 @@ void FullCodeGenerator::SetVar(Variable* var,
   if (var->IsContextSlot()) {
     int offset = Context::SlotOffset(var->index());
     DCHECK(!scratch0.is(esi) && !src.is(esi) && !scratch1.is(esi));
-    __ RecordWriteContextSlot(scratch0, offset, src, scratch1);
+    __ RecordWriteContextSlot(scratch0, offset, src, scratch1, kDontSaveFPRegs);
   }
 }
 
@@ -838,12 +836,9 @@ void FullCodeGenerator::VisitFunctionDeclaration(
       VisitForAccumulatorValue(declaration->fun());
       __ mov(ContextOperand(esi, variable->index()), result_register());
       // We know that we have written a function, which is not a smi.
-      __ RecordWriteContextSlot(esi,
-                                Context::SlotOffset(variable->index()),
-                                result_register(),
-                                ecx,
-                                EMIT_REMEMBERED_SET,
-                                OMIT_SMI_CHECK);
+      __ RecordWriteContextSlot(esi, Context::SlotOffset(variable->index()),
+                                result_register(), ecx, kDontSaveFPRegs,
+                                EMIT_REMEMBERED_SET, OMIT_SMI_CHECK);
       PrepareForBailoutForId(proxy->id(), NO_REGISTERS);
       break;
     }
@@ -877,11 +872,8 @@ void FullCodeGenerator::VisitModuleDeclaration(ModuleDeclaration* declaration) {
   // Assign it.
   __ mov(ContextOperand(esi, variable->index()), eax);
   // We know that we have written a module, which is not a smi.
-  __ RecordWriteContextSlot(esi,
-                            Context::SlotOffset(variable->index()),
-                            eax,
-                            ecx,
-                            EMIT_REMEMBERED_SET,
+  __ RecordWriteContextSlot(esi, Context::SlotOffset(variable->index()), eax,
+                            ecx, kDontSaveFPRegs, EMIT_REMEMBERED_SET,
                             OMIT_SMI_CHECK);
   PrepareForBailoutForId(declaration->proxy()->id(), NO_REGISTERS);
 
@@ -1783,9 +1775,8 @@ void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
       // Store the subexpression value in the array's elements.
       __ mov(FieldOperand(ebx, offset), result_register());
       // Update the write barrier for the array store.
-      __ RecordWriteField(ebx, offset, result_register(), ecx,
-                          EMIT_REMEMBERED_SET,
-                          INLINE_SMI_CHECK);
+      __ RecordWriteField(ebx, offset, result_register(), ecx, kDontSaveFPRegs,
+                          EMIT_REMEMBERED_SET, INLINE_SMI_CHECK);
     } else {
       // Store the subexpression value in the array's elements.
       __ mov(ecx, Immediate(Smi::FromInt(i)));
@@ -1942,7 +1933,8 @@ void FullCodeGenerator::VisitYield(Yield* expr) {
              Immediate(Smi::FromInt(continuation.pos())));
       __ mov(FieldOperand(eax, JSGeneratorObject::kContextOffset), esi);
       __ mov(ecx, esi);
-      __ RecordWriteField(eax, JSGeneratorObject::kContextOffset, ecx, edx);
+      __ RecordWriteField(eax, JSGeneratorObject::kContextOffset, ecx, edx,
+                          kDontSaveFPRegs);
       __ lea(ebx, Operand(ebp, StandardFrameConstants::kExpressionsOffset));
       __ cmp(esp, ebx);
       __ j(equal, &post_runtime);
@@ -2016,7 +2008,8 @@ void FullCodeGenerator::VisitYield(Yield* expr) {
              Immediate(Smi::FromInt(l_continuation.pos())));
       __ mov(FieldOperand(eax, JSGeneratorObject::kContextOffset), esi);
       __ mov(ecx, esi);
-      __ RecordWriteField(eax, JSGeneratorObject::kContextOffset, ecx, edx);
+      __ RecordWriteField(eax, JSGeneratorObject::kContextOffset, ecx, edx,
+                          kDontSaveFPRegs);
       __ CallRuntime(Runtime::kSuspendJSGeneratorObject, 1);
       __ mov(context_register(),
              Operand(ebp, StandardFrameConstants::kContextOffset));
@@ -2224,8 +2217,8 @@ void FullCodeGenerator::EmitCreateIteratorResult(bool done) {
 
   // Only the value field needs a write barrier, as the other values are in the
   // root set.
-  __ RecordWriteField(eax, JSGeneratorObject::kResultValuePropertyOffset,
-                      ecx, edx);
+  __ RecordWriteField(eax, JSGeneratorObject::kResultValuePropertyOffset, ecx,
+                      edx, kDontSaveFPRegs);
 }
 
 
@@ -2433,7 +2426,7 @@ void FullCodeGenerator::EmitStoreToStackLocalOrContextSlot(
   if (var->IsContextSlot()) {
     __ mov(edx, eax);
     int offset = Context::SlotOffset(var->index());
-    __ RecordWriteContextSlot(ecx, offset, edx, ebx);
+    __ RecordWriteContextSlot(ecx, offset, edx, ebx, kDontSaveFPRegs);
   }
 }
 
@@ -3532,7 +3525,7 @@ void FullCodeGenerator::EmitSetValueOf(CallRuntime* expr) {
   // Update the write barrier.  Save the value as it will be
   // overwritten by the write barrier code and is needed afterward.
   __ mov(edx, eax);
-  __ RecordWriteField(ebx, JSValue::kValueOffset, edx, ecx);
+  __ RecordWriteField(ebx, JSValue::kValueOffset, edx, ecx, kDontSaveFPRegs);
 
   __ bind(&done);
   context()->Plug(eax);
index ded2cd9..7697a1c 100644 (file)
@@ -254,10 +254,8 @@ bool LCodeGen::GeneratePrologue() {
         __ mov(Operand(esi, context_offset), eax);
         // Update the write barrier. This clobbers eax and ebx.
         if (need_write_barrier) {
-          __ RecordWriteContextSlot(esi,
-                                    context_offset,
-                                    eax,
-                                    ebx);
+          __ RecordWriteContextSlot(esi, context_offset, eax, ebx,
+                                    kDontSaveFPRegs);
         } else if (FLAG_debug_code) {
           Label done;
           __ JumpIfInNewSpace(esi, eax, &done, Label::kNear);
@@ -269,6 +267,8 @@ bool LCodeGen::GeneratePrologue() {
     Comment(";;; End allocate local context");
   }
 
+  // Initailize FPU state.
+  __ fninit();
   // Trace the call.
   if (FLAG_trace && info()->IsOptimizing()) {
     // We have not executed any compiled code yet, so esi still holds the
@@ -327,6 +327,9 @@ void LCodeGen::GenerateOsrPrologue() {
   int slots = GetStackSlotCount() - graph()->osr()->UnoptimizedFrameSlots();
   DCHECK(slots >= 1);
   __ sub(esp, Immediate((slots - 1) * kPointerSize));
+
+  // Initailize FPU state.
+  __ fninit();
 }
 
 
@@ -342,8 +345,21 @@ void LCodeGen::GenerateBodyInstructionPre(LInstruction* instr) {
 
 
 void LCodeGen::GenerateBodyInstructionPost(LInstruction* instr) {
+  // When return from function call, FPU should be initialized again.
+  if (instr->IsCall() && instr->ClobbersDoubleRegisters(isolate())) {
+    bool double_result = instr->HasDoubleRegisterResult();
+    if (double_result) {
+      __ lea(esp, Operand(esp, -kDoubleSize));
+      __ fstp_d(Operand(esp, 0));
+    }
+    __ fninit();
+    if (double_result) {
+      __ fld_d(Operand(esp, 0));
+      __ lea(esp, Operand(esp, kDoubleSize));
+    }
+  }
   if (instr->IsGoto()) {
-    x87_stack_.LeavingBlock(current_block_, LGoto::cast(instr));
+    x87_stack_.LeavingBlock(current_block_, LGoto::cast(instr), this);
   } else if (FLAG_debug_code && FLAG_enable_slow_asserts &&
              !instr->IsGap() && !instr->IsReturn()) {
     if (instr->ClobbersDoubleRegisters(isolate())) {
@@ -494,10 +510,27 @@ void LCodeGen::X87LoadForUsage(X87Register reg) {
 void LCodeGen::X87LoadForUsage(X87Register reg1, X87Register reg2) {
   DCHECK(x87_stack_.Contains(reg1));
   DCHECK(x87_stack_.Contains(reg2));
-  x87_stack_.Fxch(reg1, 1);
-  x87_stack_.Fxch(reg2);
-  x87_stack_.pop();
-  x87_stack_.pop();
+  if (reg1.is(reg2) && x87_stack_.depth() == 1) {
+    __ fld(x87_stack_.st(reg1));
+    x87_stack_.push(reg1);
+    x87_stack_.pop();
+    x87_stack_.pop();
+  } else {
+    x87_stack_.Fxch(reg1, 1);
+    x87_stack_.Fxch(reg2);
+    x87_stack_.pop();
+    x87_stack_.pop();
+  }
+}
+
+
+int LCodeGen::X87Stack::GetLayout() {
+  int layout = stack_depth_;
+  for (int i = 0; i < stack_depth_; i++) {
+    layout |= (stack_[stack_depth_ - 1 - i].code() << ((i + 1) * 3));
+  }
+
+  return layout;
 }
 
 
@@ -572,6 +605,22 @@ void LCodeGen::X87Mov(X87Register dst, Operand src, X87OperandType opts) {
 }
 
 
+void LCodeGen::X87Mov(X87Register dst, X87Register src, X87OperandType opts) {
+  if (x87_stack_.Contains(dst)) {
+    x87_stack_.Fxch(dst);
+    __ fstp(0);
+    x87_stack_.pop();
+    // Push ST(i) onto the FPU register stack
+    __ fld(x87_stack_.st(src));
+    x87_stack_.push(dst);
+  } else {
+    // Push ST(i) onto the FPU register stack
+    __ fld(x87_stack_.st(src));
+    x87_stack_.push(dst);
+  }
+}
+
+
 void LCodeGen::X87Fld(Operand src, X87OperandType opts) {
   DCHECK(!src.is_reg_only());
   switch (opts) {
@@ -597,6 +646,9 @@ void LCodeGen::X87Mov(Operand dst, X87Register src, X87OperandType opts) {
     case kX87DoubleOperand:
       __ fst_d(dst);
       break;
+    case kX87FloatOperand:
+      __ fst_s(dst);
+      break;
     case kX87IntOperand:
       __ fist_s(dst);
       break;
@@ -660,15 +712,39 @@ void LCodeGen::X87Stack::FlushIfNecessary(LInstruction* instr, LCodeGen* cgen) {
 }
 
 
-void LCodeGen::X87Stack::LeavingBlock(int current_block_id, LGoto* goto_instr) {
-  DCHECK(stack_depth_ <= 1);
-  // If ever used for new stubs producing two pairs of doubles joined into two
-  // phis this assert hits. That situation is not handled, since the two stacks
-  // might have st0 and st1 swapped.
-  if (current_block_id + 1 != goto_instr->block_id()) {
+void LCodeGen::X87Stack::LeavingBlock(int current_block_id, LGoto* goto_instr,
+                                      LCodeGen* cgen) {
+  // For going to a joined block, an explicit LClobberDoubles is inserted before
+  // LGoto. Because all used x87 registers are spilled to stack slots. The
+  // ResolvePhis phase of register allocator could guarantee the two input's x87
+  // stacks have the same layout. So don't check stack_depth_ <= 1 here.
+  int goto_block_id = goto_instr->block_id();
+  if (current_block_id + 1 != goto_block_id) {
     // If we have a value on the x87 stack on leaving a block, it must be a
     // phi input. If the next block we compile is not the join block, we have
     // to discard the stack state.
+    // Before discarding the stack state, we need to save it if the "goto block"
+    // has unreachable last predecessor when FLAG_unreachable_code_elimination.
+    if (FLAG_unreachable_code_elimination) {
+      int length = goto_instr->block()->predecessors()->length();
+      bool has_unreachable_last_predecessor = false;
+      for (int i = 0; i < length; i++) {
+        HBasicBlock* block = goto_instr->block()->predecessors()->at(i);
+        if (block->IsUnreachable() &&
+            (block->block_id() + 1) == goto_block_id) {
+          has_unreachable_last_predecessor = true;
+        }
+      }
+      if (has_unreachable_last_predecessor) {
+        if (cgen->x87_stack_map_.find(goto_block_id) ==
+            cgen->x87_stack_map_.end()) {
+          X87Stack* stack = new (cgen->zone()) X87Stack(*this);
+          cgen->x87_stack_map_.insert(std::make_pair(goto_block_id, stack));
+        }
+      }
+    }
+
+    // Discard the stack state.
     stack_depth_ = 0;
   }
 }
@@ -678,13 +754,14 @@ void LCodeGen::EmitFlushX87ForDeopt() {
   // The deoptimizer does not support X87 Registers. But as long as we
   // deopt from a stub its not a problem, since we will re-materialize the
   // original stub inputs, which can't be double registers.
-  DCHECK(info()->IsStub());
+  // DCHECK(info()->IsStub());
   if (FLAG_debug_code && FLAG_enable_slow_asserts) {
     __ pushfd();
     __ VerifyX87StackDepth(x87_stack_.depth());
     __ popfd();
   }
-  for (int i = 0; i < x87_stack_.depth(); i++) __ fstp(0);
+
+  // Flush X87 stack in the deoptimizer entry.
 }
 
 
@@ -891,6 +968,9 @@ void LCodeGen::AddToTranslation(LEnvironment* environment,
     } else {
       translation->StoreInt32Register(reg);
     }
+  } else if (op->IsDoubleRegister()) {
+    X87Register reg = ToX87Register(op);
+    translation->StoreDoubleRegister(reg);
   } else if (op->IsConstantOperand()) {
     HConstant* constant = chunk()->LookupConstant(LConstantOperand::cast(op));
     int src_index = DefineDeoptimizationLiteral(constant->handle(isolate()));
@@ -925,13 +1005,12 @@ void LCodeGen::CallCode(Handle<Code> code,
 }
 
 
-void LCodeGen::CallRuntime(const Runtime::Function* fun,
-                           int argc,
-                           LInstruction* instr) {
+void LCodeGen::CallRuntime(const Runtime::Function* fun, int argc,
+                           LInstruction* instr, SaveFPRegsMode save_doubles) {
   DCHECK(instr != NULL);
   DCHECK(instr->HasPointerMap());
 
-  __ CallRuntime(fun, argc);
+  __ CallRuntime(fun, argc, save_doubles);
 
   RecordSafepointWithLazyDeopt(instr, RECORD_SIMPLE_SAFEPOINT);
 
@@ -961,7 +1040,7 @@ void LCodeGen::CallRuntimeFromDeferred(Runtime::FunctionId id,
                                        LOperand* context) {
   LoadContextFromDeferred(context);
 
-  __ CallRuntime(id);
+  __ CallRuntimeSaveDoubles(id);
   RecordSafepointWithRegisters(
       instr->pointer_map(), argc, Safepoint::kNoLazyDeopt);
 
@@ -1035,6 +1114,12 @@ void LCodeGen::DeoptimizeIf(Condition cc, LInstruction* instr,
     __ pop(eax);
     __ popfd();
     DCHECK(frame_is_built_);
+    // Put the x87 stack layout in TOS.
+    if (x87_stack_.depth() > 0) EmitFlushX87ForDeopt();
+    __ push(Immediate(x87_stack_.GetLayout()));
+    __ fild_s(MemOperand(esp, 0));
+    // Don't touch eflags.
+    __ lea(esp, Operand(esp, kPointerSize));
     __ call(entry, RelocInfo::RUNTIME_ENTRY);
     __ bind(&no_deopt);
     __ mov(Operand::StaticVariable(count), eax);
@@ -1042,14 +1127,18 @@ void LCodeGen::DeoptimizeIf(Condition cc, LInstruction* instr,
     __ popfd();
   }
 
-  // Before Instructions which can deopt, we normally flush the x87 stack. But
-  // we can have inputs or outputs of the current instruction on the stack,
-  // thus we need to flush them here from the physical stack to leave it in a
-  // consistent state.
-  if (x87_stack_.depth() > 0) {
+  // Put the x87 stack layout in TOS, so that we can save x87 fp registers in
+  // the correct location.
+  {
     Label done;
     if (cc != no_condition) __ j(NegateCondition(cc), &done, Label::kNear);
-    EmitFlushX87ForDeopt();
+    if (x87_stack_.depth() > 0) EmitFlushX87ForDeopt();
+
+    int x87_stack_layout = x87_stack_.GetLayout();
+    __ push(Immediate(x87_stack_layout));
+    __ fild_s(MemOperand(esp, 0));
+    // Don't touch eflags.
+    __ lea(esp, Operand(esp, kPointerSize));
     __ bind(&done);
   }
 
@@ -1236,6 +1325,16 @@ void LCodeGen::DoLabel(LLabel* label) {
           LabelType(label));
   __ bind(label->label());
   current_block_ = label->block_id();
+  if (label->block()->predecessors()->length() > 1) {
+    // A join block's x87 stack is that of its last visited predecessor.
+    // If the last visited predecessor block is unreachable, the stack state
+    // will be wrong. In such case, use the x87 stack of reachable predecessor.
+    X87StackMap::const_iterator it = x87_stack_map_.find(current_block_);
+    // Restore x87 stack.
+    if (it != x87_stack_map_.end()) {
+      x87_stack_ = *(it->second);
+    }
+  }
   DoGap(label);
 }
 
@@ -1737,7 +1836,7 @@ void LCodeGen::DoMulI(LMulI* instr) {
     // Bail out if the result is supposed to be negative zero.
     Label done;
     __ test(left, Operand(left));
-    __ j(not_zero, &done, Label::kNear);
+    __ j(not_zero, &done);
     if (right->IsConstantOperand()) {
       if (ToInteger32(LConstantOperand::cast(right)) < 0) {
         DeoptimizeIf(no_condition, instr);
@@ -2118,8 +2217,58 @@ void LCodeGen::DoMathMinMax(LMathMinMax* instr) {
     }
     __ bind(&return_left);
   } else {
-    // TODO(weiliang) use X87 for double representation.
-    UNIMPLEMENTED();
+    DCHECK(instr->hydrogen()->representation().IsDouble());
+    Label check_nan_left, check_zero, return_left, return_right;
+    Condition condition = (operation == HMathMinMax::kMathMin) ? below : above;
+    X87Register left_reg = ToX87Register(left);
+    X87Register right_reg = ToX87Register(right);
+
+    X87PrepareBinaryOp(left_reg, right_reg, ToX87Register(instr->result()));
+    __ fld(1);
+    __ fld(1);
+    __ FCmp();
+    __ j(parity_even, &check_nan_left, Label::kNear);  // At least one NaN.
+    __ j(equal, &check_zero, Label::kNear);            // left == right.
+    __ j(condition, &return_left, Label::kNear);
+    __ jmp(&return_right, Label::kNear);
+
+    __ bind(&check_zero);
+    __ fld(0);
+    __ fldz();
+    __ FCmp();
+    __ j(not_equal, &return_left, Label::kNear);  // left == right != 0.
+    // At this point, both left and right are either 0 or -0.
+    if (operation == HMathMinMax::kMathMin) {
+      // Push st0 and st1 to stack, then pop them to temp registers and OR them,
+      // load it to left.
+      Register scratch_reg = ToRegister(instr->temp());
+      __ fld(1);
+      __ fld(1);
+      __ sub(esp, Immediate(2 * kPointerSize));
+      __ fstp_s(MemOperand(esp, 0));
+      __ fstp_s(MemOperand(esp, kPointerSize));
+      __ pop(scratch_reg);
+      __ xor_(MemOperand(esp, 0), scratch_reg);
+      X87Mov(left_reg, MemOperand(esp, 0), kX87FloatOperand);
+      __ pop(scratch_reg);  // restore esp
+    } else {
+      // Since we operate on +0 and/or -0, addsd and andsd have the same effect.
+      X87Fxch(left_reg);
+      __ fadd(1);
+    }
+    __ jmp(&return_left, Label::kNear);
+
+    __ bind(&check_nan_left);
+    __ fld(0);
+    __ fld(0);
+    __ FCmp();                                      // NaN check.
+    __ j(parity_even, &return_left, Label::kNear);  // left == NaN.
+
+    __ bind(&return_right);
+    X87Fxch(left_reg);
+    X87Mov(left_reg, right_reg);
+
+    __ bind(&return_left);
   }
 }
 
@@ -2164,6 +2313,13 @@ void LCodeGen::DoArithmeticD(LArithmeticD* instr) {
       UNREACHABLE();
       break;
   }
+
+  // Only always explicitly storing to memory to force the round-down for double
+  // arithmetic.
+  __ lea(esp, Operand(esp, -kDoubleSize));
+  __ fstp_d(Operand(esp, 0));
+  __ fld_d(Operand(esp, 0));
+  __ lea(esp, Operand(esp, kDoubleSize));
 }
 
 
@@ -2217,7 +2373,11 @@ void LCodeGen::DoBranch(LBranch* instr) {
     __ test(reg, Operand(reg));
     EmitBranch(instr, not_zero);
   } else if (r.IsDouble()) {
-    UNREACHABLE();
+    X87Register reg = ToX87Register(instr->value());
+    X87LoadForUsage(reg);
+    __ fldz();
+    __ FCmp();
+    EmitBranch(instr, not_zero);
   } else {
     DCHECK(r.IsTagged());
     Register reg = ToRegister(instr->value());
@@ -2473,7 +2633,10 @@ void LCodeGen::DoCompareMinusZeroAndBranch(LCompareMinusZeroAndBranch* instr) {
   DCHECK(!rep.IsInteger32());
 
   if (rep.IsDouble()) {
-    UNREACHABLE();
+    X87Register input = ToX87Register(instr->value());
+    X87LoadForUsage(input);
+    __ FXamMinusZero();
+    EmitBranch(instr, equal);
   } else {
     Register value = ToRegister(instr->value());
     Handle<Map> map = masm()->isolate()->factory()->heap_number_map();
@@ -3058,12 +3221,8 @@ void LCodeGen::DoStoreContextSlot(LStoreContextSlot* instr) {
             ? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
     Register temp = ToRegister(instr->temp());
     int offset = Context::SlotOffset(instr->slot_index());
-    __ RecordWriteContextSlot(context,
-                              offset,
-                              value,
-                              temp,
-                              EMIT_REMEMBERED_SET,
-                              check_needed);
+    __ RecordWriteContextSlot(context, offset, value, temp, kSaveFPRegs,
+                              EMIT_REMEMBERED_SET, check_needed);
   }
 
   __ bind(&skip_assignment);
@@ -3732,7 +3891,9 @@ void LCodeGen::DoMathAbs(LMathAbs* instr) {
   Representation r = instr->hydrogen()->value()->representation();
 
   if (r.IsDouble()) {
-    UNIMPLEMENTED();
+    X87Register value = ToX87Register(instr->value());
+    X87Fxch(value);
+    __ fabs();
   } else if (r.IsSmiOrInteger32()) {
     EmitIntegerMathAbs(instr);
   } else {  // Tagged case.
@@ -3748,47 +3909,350 @@ void LCodeGen::DoMathAbs(LMathAbs* instr) {
 
 
 void LCodeGen::DoMathFloor(LMathFloor* instr) {
-  UNIMPLEMENTED();
+  Register output_reg = ToRegister(instr->result());
+  X87Register input_reg = ToX87Register(instr->value());
+  X87Fxch(input_reg);
+
+  Label not_minus_zero, done;
+  // Deoptimize on unordered.
+  __ fldz();
+  __ fld(1);
+  __ FCmp();
+  DeoptimizeIf(parity_even, instr);
+  __ j(below, &not_minus_zero, Label::kNear);
+
+  if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
+    // Check for negative zero.
+    __ j(not_equal, &not_minus_zero, Label::kNear);
+    // +- 0.0.
+    __ fld(0);
+    __ FXamSign();
+    DeoptimizeIf(not_zero, instr);
+    __ Move(output_reg, Immediate(0));
+    __ jmp(&done, Label::kFar);
+  }
+
+  // Positive input.
+  // rc=01B, round down.
+  __ bind(&not_minus_zero);
+  __ fnclex();
+  __ X87SetRC(0x0400);
+  __ sub(esp, Immediate(kPointerSize));
+  __ fist_s(Operand(esp, 0));
+  __ pop(output_reg);
+  __ X87CheckIA();
+  DeoptimizeIf(equal, instr);
+  __ fnclex();
+  __ X87SetRC(0x0000);
+  __ bind(&done);
 }
 
 
 void LCodeGen::DoMathRound(LMathRound* instr) {
-  UNIMPLEMENTED();
+  X87Register input_reg = ToX87Register(instr->value());
+  Register result = ToRegister(instr->result());
+  X87Fxch(input_reg);
+  Label below_one_half, below_minus_one_half, done;
+
+  ExternalReference one_half = ExternalReference::address_of_one_half();
+  ExternalReference minus_one_half =
+      ExternalReference::address_of_minus_one_half();
+
+  __ fld_d(Operand::StaticVariable(one_half));
+  __ fld(1);
+  __ FCmp();
+  __ j(carry, &below_one_half);
+
+  // Use rounds towards zero, since 0.5 <= x, we use floor(0.5 + x)
+  __ fld(0);
+  __ fadd_d(Operand::StaticVariable(one_half));
+  // rc=11B, round toward zero.
+  __ X87SetRC(0x0c00);
+  __ sub(esp, Immediate(kPointerSize));
+  // Clear exception bits.
+  __ fnclex();
+  __ fistp_s(MemOperand(esp, 0));
+  // Check overflow.
+  __ X87CheckIA();
+  __ RecordComment("D2I conversion overflow");
+  __ pop(result);
+  DeoptimizeIf(equal, instr);
+  __ fnclex();
+  // Restore round mode.
+  __ X87SetRC(0x0000);
+  __ jmp(&done);
+
+  __ bind(&below_one_half);
+  __ fld_d(Operand::StaticVariable(minus_one_half));
+  __ fld(1);
+  __ FCmp();
+  __ j(carry, &below_minus_one_half);
+  // We return 0 for the input range [+0, 0.5[, or [-0.5, 0.5[ if
+  // we can ignore the difference between a result of -0 and +0.
+  if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
+    // If the sign is positive, we return +0.
+    __ fld(0);
+    __ FXamSign();
+    __ RecordComment("Minus zero");
+    DeoptimizeIf(not_zero, instr);
+  }
+  __ Move(result, Immediate(0));
+  __ jmp(&done);
+
+  __ bind(&below_minus_one_half);
+  __ fld(0);
+  __ fadd_d(Operand::StaticVariable(one_half));
+  // rc=01B, round down.
+  __ X87SetRC(0x0400);
+  __ sub(esp, Immediate(kPointerSize));
+  // Clear exception bits.
+  __ fnclex();
+  __ fistp_s(MemOperand(esp, 0));
+  // Check overflow.
+  __ X87CheckIA();
+  __ RecordComment("D2I conversion overflow");
+  __ pop(result);
+  DeoptimizeIf(equal, instr);
+  __ fnclex();
+  // Restore round mode.
+  __ X87SetRC(0x0000);
+
+  __ bind(&done);
 }
 
 
 void LCodeGen::DoMathFround(LMathFround* instr) {
-  UNIMPLEMENTED();
+  X87Register input_reg = ToX87Register(instr->value());
+  X87Fxch(input_reg);
+  __ sub(esp, Immediate(kPointerSize));
+  __ fstp_s(MemOperand(esp, 0));
+  X87Fld(MemOperand(esp, 0), kX87FloatOperand);
+  __ add(esp, Immediate(kPointerSize));
 }
 
 
 void LCodeGen::DoMathSqrt(LMathSqrt* instr) {
-  UNIMPLEMENTED();
+  X87Register input_reg = ToX87Register(instr->value());
+  X87Register output_reg = ToX87Register(instr->result());
+  DCHECK(output_reg.is(input_reg));
+  USE(output_reg);
+  X87Fxch(input_reg);
+  __ fsqrt();
 }
 
 
 void LCodeGen::DoMathPowHalf(LMathPowHalf* instr) {
-  UNIMPLEMENTED();
+  X87Register input_reg = ToX87Register(instr->value());
+  DCHECK(ToX87Register(instr->result()).is(input_reg));
+  X87Fxch(input_reg);
+  // Note that according to ECMA-262 15.8.2.13:
+  // Math.pow(-Infinity, 0.5) == Infinity
+  // Math.sqrt(-Infinity) == NaN
+  Label done, sqrt;
+  // Check base for -Infinity. C3 == 0, C2 == 1, C1 == 1 and C0 == 1
+  __ fxam();
+  __ push(eax);
+  __ fnstsw_ax();
+  __ and_(eax, Immediate(0x4700));
+  __ cmp(eax, Immediate(0x0700));
+  __ j(not_equal, &sqrt, Label::kNear);
+  // If input is -Infinity, return Infinity.
+  __ fchs();
+  __ jmp(&done, Label::kNear);
+
+  // Square root.
+  __ bind(&sqrt);
+  __ fldz();
+  __ faddp();  // Convert -0 to +0.
+  __ fsqrt();
+  __ bind(&done);
+  __ pop(eax);
 }
 
 
 void LCodeGen::DoPower(LPower* instr) {
-  UNIMPLEMENTED();
+  Representation exponent_type = instr->hydrogen()->right()->representation();
+  X87Register result = ToX87Register(instr->result());
+  // Having marked this as a call, we can use any registers.
+  X87Register base = ToX87Register(instr->left());
+  ExternalReference one_half = ExternalReference::address_of_one_half();
+
+  if (exponent_type.IsSmi()) {
+    Register exponent = ToRegister(instr->right());
+    X87LoadForUsage(base);
+    __ SmiUntag(exponent);
+    __ push(exponent);
+    __ fild_s(MemOperand(esp, 0));
+    __ pop(exponent);
+  } else if (exponent_type.IsTagged()) {
+    Register exponent = ToRegister(instr->right());
+    Register temp = exponent.is(ecx) ? eax : ecx;
+    Label no_deopt, done;
+    X87LoadForUsage(base);
+    __ JumpIfSmi(exponent, &no_deopt);
+    __ CmpObjectType(exponent, HEAP_NUMBER_TYPE, temp);
+    DeoptimizeIf(not_equal, instr);
+    // Heap number(double)
+    __ fld_d(FieldOperand(exponent, HeapNumber::kValueOffset));
+    __ jmp(&done);
+    // SMI
+    __ bind(&no_deopt);
+    __ SmiUntag(exponent);
+    __ push(exponent);
+    __ fild_s(MemOperand(esp, 0));
+    __ pop(exponent);
+    __ bind(&done);
+  } else if (exponent_type.IsInteger32()) {
+    Register exponent = ToRegister(instr->right());
+    X87LoadForUsage(base);
+    __ push(exponent);
+    __ fild_s(MemOperand(esp, 0));
+    __ pop(exponent);
+  } else {
+    DCHECK(exponent_type.IsDouble());
+    X87Register exponent_double = ToX87Register(instr->right());
+    X87LoadForUsage(base, exponent_double);
+  }
+
+  // FP data stack {base, exponent(TOS)}.
+  // Handle (exponent==+-0.5 && base == -0).
+  Label not_plus_0;
+  __ fld(0);
+  __ fabs();
+  X87Fld(Operand::StaticVariable(one_half), kX87DoubleOperand);
+  __ FCmp();
+  __ j(parity_even, &not_plus_0, Label::kNear);  // NaN.
+  __ j(not_equal, &not_plus_0, Label::kNear);
+  __ fldz();
+  // FP data stack {base, exponent(TOS), zero}.
+  __ faddp(2);
+  __ bind(&not_plus_0);
+
+  {
+    __ PrepareCallCFunction(4, eax);
+    __ fstp_d(MemOperand(esp, kDoubleSize));  // Exponent value.
+    __ fstp_d(MemOperand(esp, 0));            // Base value.
+    X87PrepareToWrite(result);
+    __ CallCFunction(ExternalReference::power_double_double_function(isolate()),
+                     4);
+    // Return value is in st(0) on ia32.
+    X87CommitWrite(result);
+  }
 }
 
 
 void LCodeGen::DoMathLog(LMathLog* instr) {
-  UNIMPLEMENTED();
+  DCHECK(instr->value()->Equals(instr->result()));
+  X87Register input_reg = ToX87Register(instr->value());
+  X87Fxch(input_reg);
+
+  Label positive, done, zero, nan_result;
+  __ fldz();
+  __ fld(1);
+  __ FCmp();
+  __ j(below, &nan_result, Label::kNear);
+  __ j(equal, &zero, Label::kNear);
+  // Positive input.
+  // {input, ln2}.
+  __ fldln2();
+  // {ln2, input}.
+  __ fxch();
+  // {result}.
+  __ fyl2x();
+  __ jmp(&done, Label::kNear);
+
+  __ bind(&nan_result);
+  ExternalReference nan =
+      ExternalReference::address_of_canonical_non_hole_nan();
+  X87PrepareToWrite(input_reg);
+  __ fld_d(Operand::StaticVariable(nan));
+  X87CommitWrite(input_reg);
+  __ jmp(&done, Label::kNear);
+
+  __ bind(&zero);
+  ExternalReference ninf = ExternalReference::address_of_negative_infinity();
+  X87PrepareToWrite(input_reg);
+  __ fld_d(Operand::StaticVariable(ninf));
+  X87CommitWrite(input_reg);
+
+  __ bind(&done);
 }
 
 
 void LCodeGen::DoMathClz32(LMathClz32* instr) {
-  UNIMPLEMENTED();
+  Register input = ToRegister(instr->value());
+  Register result = ToRegister(instr->result());
+  Label not_zero_input;
+  __ bsr(result, input);
+
+  __ j(not_zero, &not_zero_input);
+  __ Move(result, Immediate(63));  // 63^31 == 32
+
+  __ bind(&not_zero_input);
+  __ xor_(result, Immediate(31));  // for x in [0..31], 31^x == 31-x.
 }
 
 
 void LCodeGen::DoMathExp(LMathExp* instr) {
-  UNIMPLEMENTED();
+  X87Register input = ToX87Register(instr->value());
+  X87Register result_reg = ToX87Register(instr->result());
+  Register temp_result = ToRegister(instr->temp1());
+  Register temp = ToRegister(instr->temp2());
+  Label slow, done, smi, finish;
+  DCHECK(result_reg.is(input));
+
+  // Store input into Heap number and call runtime function kMathExpRT.
+  if (FLAG_inline_new) {
+    __ AllocateHeapNumber(temp_result, temp, no_reg, &slow);
+    __ jmp(&done, Label::kNear);
+  }
+
+  // Slow case: Call the runtime system to do the number allocation.
+  __ bind(&slow);
+  {
+    // TODO(3095996): Put a valid pointer value in the stack slot where the
+    // result register is stored, as this register is in the pointer map, but
+    // contains an integer value.
+    __ Move(temp_result, Immediate(0));
+
+    // Preserve the value of all registers.
+    PushSafepointRegistersScope scope(this);
+
+    __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
+    __ CallRuntimeSaveDoubles(Runtime::kAllocateHeapNumber);
+    RecordSafepointWithRegisters(instr->pointer_map(), 0,
+                                 Safepoint::kNoLazyDeopt);
+    __ StoreToSafepointRegisterSlot(temp_result, eax);
+  }
+  __ bind(&done);
+  X87LoadForUsage(input);
+  __ fstp_d(FieldOperand(temp_result, HeapNumber::kValueOffset));
+
+  {
+    // Preserve the value of all registers.
+    PushSafepointRegistersScope scope(this);
+
+    __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
+    __ push(temp_result);
+    __ CallRuntimeSaveDoubles(Runtime::kMathExpRT);
+    RecordSafepointWithRegisters(instr->pointer_map(), 0,
+                                 Safepoint::kNoLazyDeopt);
+    __ StoreToSafepointRegisterSlot(temp_result, eax);
+  }
+  X87PrepareToWrite(result_reg);
+  // return value of MathExpRT is Smi or Heap Number.
+  __ JumpIfSmi(temp_result, &smi);
+  // Heap number(double)
+  __ fld_d(FieldOperand(temp_result, HeapNumber::kValueOffset));
+  __ jmp(&finish);
+  // SMI
+  __ bind(&smi);
+  __ SmiUntag(temp_result);
+  __ push(temp_result);
+  __ fild_s(MemOperand(esp, 0));
+  __ pop(temp_result);
+  __ bind(&finish);
+  X87CommitWrite(result_reg);
 }
 
 
@@ -3885,7 +4349,7 @@ void LCodeGen::DoCallNewArray(LCallNewArray* instr) {
 
 void LCodeGen::DoCallRuntime(LCallRuntime* instr) {
   DCHECK(ToRegister(instr->context()).is(esi));
-  CallRuntime(instr->function(), instr->arity(), instr);
+  CallRuntime(instr->function(), instr->arity(), instr, instr->save_doubles());
 }
 
 
@@ -3956,7 +4420,7 @@ void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) {
       __ mov(temp_map, transition);
       __ mov(FieldOperand(object, HeapObject::kMapOffset), temp_map);
       // Update the write barrier for the map field.
-      __ RecordWriteForMap(object, transition, temp_map, temp);
+      __ RecordWriteForMap(object, transition, temp_map, temp, kSaveFPRegs);
     }
   }
 
@@ -3991,10 +4455,7 @@ void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) {
     Register value = ToRegister(instr->value());
     Register temp = access.IsInobject() ? ToRegister(instr->temp()) : object;
     // Update the write barrier for the object for in-object properties.
-    __ RecordWriteField(write_register,
-                        offset,
-                        value,
-                        temp,
+    __ RecordWriteField(write_register, offset, value, temp, kSaveFPRegs,
                         EMIT_REMEMBERED_SET,
                         instr->hydrogen()->SmiCheckForWriteBarrier(),
                         instr->hydrogen()->PointersToHereCheckForValue());
@@ -4054,8 +4515,7 @@ void LCodeGen::DoStoreKeyedExternalArray(LStoreKeyed* instr) {
       instr->base_offset()));
   if (elements_kind == EXTERNAL_FLOAT32_ELEMENTS ||
       elements_kind == FLOAT32_ELEMENTS) {
-    __ fld(0);
-    __ fstp_s(operand);
+    X87Mov(operand, ToX87Register(instr->value()), kX87FloatOperand);
   } else if (elements_kind == EXTERNAL_FLOAT64_ELEMENTS ||
              elements_kind == FLOAT64_ELEMENTS) {
     X87Mov(operand, ToX87Register(instr->value()));
@@ -4191,10 +4651,7 @@ void LCodeGen::DoStoreKeyedFixedArray(LStoreKeyed* instr) {
           ? OMIT_SMI_CHECK : INLINE_SMI_CHECK;
     // Compute address of modified element and store it into key register.
     __ lea(key, operand);
-    __ RecordWrite(elements,
-                   key,
-                   value,
-                   EMIT_REMEMBERED_SET,
+    __ RecordWrite(elements, key, value, kSaveFPRegs, EMIT_REMEMBERED_SET,
                    check_needed,
                    instr->hydrogen()->PointersToHereCheckForValue());
   }
@@ -4257,7 +4714,7 @@ void LCodeGen::DoTransitionElementsKind(LTransitionElementsKind* instr) {
     // Write barrier.
     DCHECK_NE(instr->temp(), NULL);
     __ RecordWriteForMap(object_reg, to_map, new_map_reg,
-                         ToRegister(instr->temp()));
+                         ToRegister(instr->temp()), kDontSaveFPRegs);
   } else {
     DCHECK(ToRegister(instr->context()).is(esi));
     DCHECK(object_reg.is(eax));
@@ -4527,7 +4984,7 @@ void LCodeGen::DoDeferredNumberTagIU(LInstruction* instr,
     // The corresponding HChange instructions are added in a phase that does
     // not have easy access to the local context.
     __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
-    __ CallRuntime(Runtime::kAllocateHeapNumber);
+    __ CallRuntimeSaveDoubles(Runtime::kAllocateHeapNumber);
     RecordSafepointWithRegisters(
         instr->pointer_map(), 0, Safepoint::kNoLazyDeopt);
     __ StoreToSafepointRegisterSlot(reg, eax);
@@ -4557,7 +5014,9 @@ void LCodeGen::DoNumberTagD(LNumberTagD* instr) {
 
   // Put the value to the top of stack
   X87Register src = ToX87Register(instr->value());
-  X87LoadForUsage(src);
+  // Don't use X87LoadForUsage here, which is only used by Instruction which
+  // clobbers fp registers.
+  x87_stack_.Fxch(src);
 
   DeferredNumberTagD* deferred =
       new(zone()) DeferredNumberTagD(this, instr, x87_stack_);
@@ -4568,7 +5027,7 @@ void LCodeGen::DoNumberTagD(LNumberTagD* instr) {
     __ jmp(deferred->entry());
   }
   __ bind(deferred->exit());
-  __ fstp_d(FieldOperand(reg, HeapNumber::kValueOffset));
+  __ fst_d(FieldOperand(reg, HeapNumber::kValueOffset));
 }
 
 
@@ -4586,7 +5045,7 @@ void LCodeGen::DoDeferredNumberTagD(LNumberTagD* instr) {
   // The corresponding HChange instructions are added in a phase that does
   // not have easy access to the local context.
   __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
-  __ CallRuntime(Runtime::kAllocateHeapNumber);
+  __ CallRuntimeSaveDoubles(Runtime::kAllocateHeapNumber);
   RecordSafepointWithRegisters(
       instr->pointer_map(), 0, Safepoint::kNoLazyDeopt);
   __ StoreToSafepointRegisterSlot(reg, eax);
@@ -4635,7 +5094,7 @@ void LCodeGen::EmitNumberUntagDNoSSE2(LNumberUntagD* instr, Register input_reg,
   X87PrepareToWrite(res_reg);
   if (mode == NUMBER_CANDIDATE_IS_ANY_TAGGED) {
     // Smi check.
-    __ JumpIfSmi(input_reg, &load_smi, Label::kNear);
+    __ JumpIfSmi(input_reg, &load_smi);
 
     // Heap number map check.
     __ cmp(FieldOperand(input_reg, HeapObject::kMapOffset),
@@ -4644,7 +5103,7 @@ void LCodeGen::EmitNumberUntagDNoSSE2(LNumberUntagD* instr, Register input_reg,
       DeoptimizeIf(not_equal, instr);
     } else {
       Label heap_number, convert;
-      __ j(equal, &heap_number, Label::kNear);
+      __ j(equal, &heap_number);
 
       // Convert undefined (or hole) to NaN.
       __ cmp(input_reg, factory()->undefined_value());
@@ -4973,7 +5432,7 @@ void LCodeGen::DoDeferredInstanceMigration(LCheckMaps* instr, Register object) {
     PushSafepointRegistersScope scope(this);
     __ push(object);
     __ xor_(esi, esi);
-    __ CallRuntime(Runtime::kTryMigrateInstance);
+    __ CallRuntimeSaveDoubles(Runtime::kTryMigrateInstance);
     RecordSafepointWithRegisters(
         instr->pointer_map(), 1, Safepoint::kNoLazyDeopt);
 
@@ -5043,7 +5502,10 @@ void LCodeGen::DoCheckMaps(LCheckMaps* instr) {
 
 
 void LCodeGen::DoClampDToUint8(LClampDToUint8* instr) {
-  UNREACHABLE();
+  X87Register value_reg = ToX87Register(instr->unclamped());
+  Register result_reg = ToRegister(instr->result());
+  X87Fxch(value_reg);
+  __ ClampTOSToUint8(result_reg);
 }
 
 
@@ -5177,12 +5639,32 @@ void LCodeGen::DoClampTToUint8NoSSE2(LClampTToUint8NoSSE2* instr) {
 
 
 void LCodeGen::DoDoubleBits(LDoubleBits* instr) {
-  UNREACHABLE();
+  X87Register value_reg = ToX87Register(instr->value());
+  Register result_reg = ToRegister(instr->result());
+  X87Fxch(value_reg);
+  __ sub(esp, Immediate(kDoubleSize));
+  __ fst_d(Operand(esp, 0));
+  if (instr->hydrogen()->bits() == HDoubleBits::HIGH) {
+    __ mov(result_reg, Operand(esp, kPointerSize));
+  } else {
+    __ mov(result_reg, Operand(esp, 0));
+  }
+  __ add(esp, Immediate(kDoubleSize));
 }
 
 
 void LCodeGen::DoConstructDouble(LConstructDouble* instr) {
-  UNREACHABLE();
+  Register hi_reg = ToRegister(instr->hi());
+  Register lo_reg = ToRegister(instr->lo());
+  X87Register result_reg = ToX87Register(instr->result());
+  // Follow below pattern to write a x87 fp register.
+  X87PrepareToWrite(result_reg);
+  __ sub(esp, Immediate(kDoubleSize));
+  __ mov(Operand(esp, 0), lo_reg);
+  __ mov(Operand(esp, kPointerSize), hi_reg);
+  __ fld_d(Operand(esp, 0));
+  __ add(esp, Immediate(kDoubleSize));
+  X87CommitWrite(result_reg);
 }
 
 
@@ -5546,7 +6028,7 @@ void LCodeGen::DoDummyUse(LDummyUse* instr) {
 void LCodeGen::DoDeferredStackCheck(LStackCheck* instr) {
   PushSafepointRegistersScope scope(this);
   __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
-  __ CallRuntime(Runtime::kStackGuard);
+  __ CallRuntimeSaveDoubles(Runtime::kStackGuard);
   RecordSafepointWithLazyDeopt(
       instr, RECORD_SAFEPOINT_WITH_REGISTERS_AND_NO_ARGUMENTS);
   DCHECK(instr->HasEnvironment());
@@ -5693,7 +6175,7 @@ void LCodeGen::DoDeferredLoadMutableDouble(LLoadFieldByIndex* instr,
   __ push(object);
   __ push(index);
   __ xor_(esi, esi);
-  __ CallRuntime(Runtime::kLoadMutableDouble);
+  __ CallRuntimeSaveDoubles(Runtime::kLoadMutableDouble);
   RecordSafepointWithRegisters(
       instr->pointer_map(), 2, Safepoint::kNoLazyDeopt);
   __ StoreToSafepointRegisterSlot(object, eax);
index 080a468..88d2810 100644 (file)
@@ -5,6 +5,7 @@
 #ifndef V8_X87_LITHIUM_CODEGEN_X87_H_
 #define V8_X87_LITHIUM_CODEGEN_X87_H_
 
+#include <map>
 #include "src/x87/lithium-x87.h"
 
 #include "src/base/logging.h"
@@ -84,6 +85,8 @@ class LCodeGen: public LCodeGenBase {
       X87OperandType operand = kX87DoubleOperand);
   void X87Mov(Operand src, X87Register reg,
       X87OperandType operand = kX87DoubleOperand);
+  void X87Mov(X87Register reg, X87Register src,
+              X87OperandType operand = kX87DoubleOperand);
 
   void X87PrepareBinaryOp(
       X87Register left, X87Register right, X87Register result);
@@ -198,9 +201,8 @@ class LCodeGen: public LCodeGenBase {
                        LInstruction* instr,
                        SafepointMode safepoint_mode);
 
-  void CallRuntime(const Runtime::Function* fun,
-                   int argc,
-                   LInstruction* instr);
+  void CallRuntime(const Runtime::Function* fun, int argc, LInstruction* instr,
+                   SaveFPRegsMode save_doubles = kDontSaveFPRegs);
 
   void CallRuntime(Runtime::FunctionId id,
                    int argc,
@@ -376,7 +378,7 @@ class LCodeGen: public LCodeGenBase {
   int osr_pc_offset_;
   bool frame_is_built_;
 
-  class X87Stack {
+  class X87Stack : public ZoneObject {
    public:
     explicit X87Stack(MacroAssembler* masm)
         : stack_depth_(0), is_mutable_(true), masm_(masm) { }
@@ -393,14 +395,23 @@ class LCodeGen: public LCodeGenBase {
       }
       return true;
     }
+    X87Stack& operator=(const X87Stack& other) {
+      stack_depth_ = other.stack_depth_;
+      for (int i = 0; i < stack_depth_; i++) {
+        stack_[i] = other.stack_[i];
+      }
+      return *this;
+    }
     bool Contains(X87Register reg);
     void Fxch(X87Register reg, int other_slot = 0);
     void Free(X87Register reg);
     void PrepareToWrite(X87Register reg);
     void CommitWrite(X87Register reg);
     void FlushIfNecessary(LInstruction* instr, LCodeGen* cgen);
-    void LeavingBlock(int current_block_id, LGoto* goto_instr);
+    void LeavingBlock(int current_block_id, LGoto* goto_instr, LCodeGen* cgen);
     int depth() const { return stack_depth_; }
+    int GetLayout();
+    int st(X87Register reg) { return st2idx(ArrayIndex(reg)); }
     void pop() {
       DCHECK(is_mutable_);
       stack_depth_--;
@@ -425,6 +436,9 @@ class LCodeGen: public LCodeGenBase {
     MacroAssembler* masm_;
   };
   X87Stack x87_stack_;
+  // block_id -> X87Stack*;
+  typedef std::map<int, X87Stack*> X87StackMap;
+  X87StackMap x87_stack_map_;
 
   // Builder that keeps track of safepoints in the code. The table
   // itself is emitted at the end of the generated code.
@@ -458,6 +472,7 @@ class LCodeGen: public LCodeGenBase {
   friend class LDeferredCode;
   friend class LEnvironment;
   friend class SafepointGenerator;
+  friend class X87Stack;
   DISALLOW_COPY_AND_ASSIGN(LCodeGen);
 };
 
index b94e34f..6a64275 100644 (file)
@@ -317,10 +317,15 @@ void LGapResolver::EmitMove(int index) {
   } else if (source->IsDoubleRegister()) {
     // load from the register onto the stack, store in destination, which must
     // be a double stack slot in the non-SSE2 case.
-    DCHECK(destination->IsDoubleStackSlot());
-    Operand dst = cgen_->ToOperand(destination);
-    X87Register src = cgen_->ToX87Register(source);
-    cgen_->X87Mov(dst, src);
+    if (destination->IsDoubleStackSlot()) {
+      Operand dst = cgen_->ToOperand(destination);
+      X87Register src = cgen_->ToX87Register(source);
+      cgen_->X87Mov(dst, src);
+    } else {
+      X87Register dst = cgen_->ToX87Register(destination);
+      X87Register src = cgen_->ToX87Register(source);
+      cgen_->X87Mov(dst, src);
+    }
   } else if (source->IsDoubleStackSlot()) {
     // load from the stack slot on top of the floating point stack, and then
     // store in destination. If destination is a double register, then it
index 02037c3..993f5ad 100644 (file)
@@ -484,6 +484,12 @@ LUnallocated* LChunkBuilder::ToUnallocated(Register reg) {
 }
 
 
+LUnallocated* LChunkBuilder::ToUnallocated(X87Register reg) {
+  return new (zone()) LUnallocated(LUnallocated::FIXED_DOUBLE_REGISTER,
+                                   X87Register::ToAllocationIndex(reg));
+}
+
+
 LOperand* LChunkBuilder::UseFixed(HValue* value, Register fixed_register) {
   return Use(value, ToUnallocated(fixed_register));
 }
@@ -616,6 +622,12 @@ LInstruction* LChunkBuilder::DefineFixed(LTemplateResultInstruction<1>* instr,
 }
 
 
+LInstruction* LChunkBuilder::DefineFixed(LTemplateResultInstruction<1>* instr,
+                                         X87Register reg) {
+  return Define(instr, ToUnallocated(reg));
+}
+
+
 LInstruction* LChunkBuilder::AssignEnvironment(LInstruction* instr) {
   HEnvironment* hydrogen_env = current_block_->last_environment();
   int argument_index_accumulator = 0;
@@ -872,6 +884,14 @@ void LChunkBuilder::VisitInstruction(HInstruction* current) {
     if (current->IsControlInstruction() &&
         HControlInstruction::cast(current)->KnownSuccessorBlock(&successor) &&
         successor != NULL) {
+      // Always insert a fpu register barrier here when branch is optimized to
+      // be a direct goto.
+      // TODO(weiliang): require a better solution.
+      if (!current->IsGoto()) {
+        LClobberDoubles* clobber = new (zone()) LClobberDoubles(isolate());
+        clobber->set_hydrogen_value(current);
+        chunk_->AddInstruction(clobber, current_block_);
+      }
       instr = new(zone()) LGoto(successor);
     } else {
       instr = current->CompileToLithium(this);
@@ -931,7 +951,8 @@ void LChunkBuilder::AddInstruction(LInstruction* instr,
   if (FLAG_stress_environments && !instr->HasEnvironment()) {
     instr = AssignEnvironment(instr);
   }
-  if (instr->IsGoto() && LGoto::cast(instr)->jumps_to_join()) {
+  if (instr->IsGoto() &&
+      (LGoto::cast(instr)->jumps_to_join() || next_block_->is_osr_entry())) {
     // TODO(olivf) Since phis of spilled values are joined as registers
     // (not in the stack slot), we need to allow the goto gaps to keep one
     // x87 register alive. To ensure all other values are still spilled, we
@@ -979,7 +1000,9 @@ LInstruction* LChunkBuilder::DoBranch(HBranch* instr) {
   bool easy_case = !r.IsTagged() || type.IsBoolean() || type.IsSmi() ||
       type.IsJSArray() || type.IsHeapNumber() || type.IsString();
   LOperand* temp = !easy_case && expected.NeedsMap() ? TempRegister() : NULL;
-  LInstruction* branch = new(zone()) LBranch(UseRegister(value), temp);
+  LInstruction* branch =
+      temp != NULL ? new (zone()) LBranch(UseRegister(value), temp)
+                   : new (zone()) LBranch(UseRegisterAtStart(value), temp);
   if (!easy_case &&
       ((!expected.Contains(ToBooleanStub::SMI) && expected.NeedsMap()) ||
        !expected.IsGeneric())) {
@@ -1182,16 +1205,16 @@ LInstruction* LChunkBuilder::DoMathFloor(HUnaryMathOperation* instr) {
 
 
 LInstruction* LChunkBuilder::DoMathRound(HUnaryMathOperation* instr) {
-  // Crankshaft is turned off for nosse2.
-  UNREACHABLE();
-  return NULL;
+  LOperand* input = UseRegisterAtStart(instr->value());
+  LInstruction* result = DefineAsRegister(new (zone()) LMathRound(input));
+  return AssignEnvironment(result);
 }
 
 
 LInstruction* LChunkBuilder::DoMathFround(HUnaryMathOperation* instr) {
-  LOperand* input = UseRegisterAtStart(instr->value());
+  LOperand* input = UseRegister(instr->value());
   LMathFround* result = new (zone()) LMathFround(input);
-  return AssignEnvironment(DefineAsRegister(result));
+  return DefineSameAsFirst(result);
 }
 
 
@@ -1225,11 +1248,11 @@ LInstruction* LChunkBuilder::DoMathClz32(HUnaryMathOperation* instr) {
 LInstruction* LChunkBuilder::DoMathExp(HUnaryMathOperation* instr) {
   DCHECK(instr->representation().IsDouble());
   DCHECK(instr->value()->representation().IsDouble());
-  LOperand* value = UseTempRegister(instr->value());
-  LOperand* temp1 = TempRegister();
-  LOperand* temp2 = TempRegister();
+  LOperand* value = UseRegisterAtStart(instr->value());
+  LOperand* temp1 = FixedTemp(ecx);
+  LOperand* temp2 = FixedTemp(edx);
   LMathExp* result = new(zone()) LMathExp(value, temp1, temp2);
-  return DefineAsRegister(result);
+  return MarkAsCall(DefineSameAsFirst(result), instr);
 }
 
 
@@ -1242,8 +1265,7 @@ LInstruction* LChunkBuilder::DoMathSqrt(HUnaryMathOperation* instr) {
 
 LInstruction* LChunkBuilder::DoMathPowHalf(HUnaryMathOperation* instr) {
   LOperand* input = UseRegisterAtStart(instr->value());
-  LOperand* temp = TempRegister();
-  LMathPowHalf* result = new(zone()) LMathPowHalf(input, temp);
+  LMathPowHalf* result = new (zone()) LMathPowHalf(input);
   return DefineSameAsFirst(result);
 }
 
@@ -1615,6 +1637,8 @@ LInstruction* LChunkBuilder::DoAdd(HAdd* instr) {
 LInstruction* LChunkBuilder::DoMathMinMax(HMathMinMax* instr) {
   LOperand* left = NULL;
   LOperand* right = NULL;
+  LOperand* scratch = TempRegister();
+
   if (instr->representation().IsSmiOrInteger32()) {
     DCHECK(instr->left()->representation().Equals(instr->representation()));
     DCHECK(instr->right()->representation().Equals(instr->representation()));
@@ -1627,15 +1651,19 @@ LInstruction* LChunkBuilder::DoMathMinMax(HMathMinMax* instr) {
     left = UseRegisterAtStart(instr->left());
     right = UseRegisterAtStart(instr->right());
   }
-  LMathMinMax* minmax = new(zone()) LMathMinMax(left, right);
+  LMathMinMax* minmax = new (zone()) LMathMinMax(left, right, scratch);
   return DefineSameAsFirst(minmax);
 }
 
 
 LInstruction* LChunkBuilder::DoPower(HPower* instr) {
-  // Crankshaft is turned off for nosse2.
-  UNREACHABLE();
-  return NULL;
+  // Unlike ia32, we don't have a MathPowStub and directly call c function.
+  DCHECK(instr->representation().IsDouble());
+  DCHECK(instr->left()->representation().IsDouble());
+  LOperand* left = UseRegisterAtStart(instr->left());
+  LOperand* right = UseRegisterAtStart(instr->right());
+  LPower* result = new (zone()) LPower(left, right);
+  return MarkAsCall(DefineSameAsFirst(result), instr);
 }
 
 
@@ -1697,9 +1725,8 @@ LInstruction* LChunkBuilder::DoCompareHoleAndBranch(
 
 LInstruction* LChunkBuilder::DoCompareMinusZeroAndBranch(
     HCompareMinusZeroAndBranch* instr) {
-  LOperand* value = UseRegister(instr->value());
-  LOperand* scratch = TempRegister();
-  return new(zone()) LCompareMinusZeroAndBranch(value, scratch);
+  LOperand* value = UseRegisterAtStart(instr->value());
+  return new (zone()) LCompareMinusZeroAndBranch(value);
 }
 
 
@@ -2022,8 +2049,8 @@ LInstruction* LChunkBuilder::DoClampToUint8(HClampToUint8* instr) {
   HValue* value = instr->value();
   Representation input_rep = value->representation();
   if (input_rep.IsDouble()) {
-    UNREACHABLE();
-    return NULL;
+    LOperand* reg = UseRegister(value);
+    return DefineFixed(new (zone()) LClampDToUint8(reg), eax);
   } else if (input_rep.IsInteger32()) {
     LOperand* reg = UseFixed(value, eax);
     return DefineFixed(new(zone()) LClampIToUint8(reg), eax);
index 233eaf2..e5cced2 100644 (file)
@@ -413,6 +413,7 @@ class LGoto FINAL : public LTemplateInstruction<0, 0, 0> {
   }
 
   bool jumps_to_join() const { return block_->predecessors()->length() > 1; }
+  HBasicBlock* block() const { return block_; }
 
  private:
   HBasicBlock* block_;
@@ -984,15 +985,11 @@ class LMathSqrt FINAL : public LTemplateInstruction<1, 1, 0> {
 };
 
 
-class LMathPowHalf FINAL : public LTemplateInstruction<1, 1, 1> {
+class LMathPowHalf FINAL : public LTemplateInstruction<1, 1, 0> {
  public:
-  LMathPowHalf(LOperand* value, LOperand* temp) {
-    inputs_[0] = value;
-    temps_[0] = temp;
-  }
+  explicit LMathPowHalf(LOperand* value) { inputs_[0] = value; }
 
   LOperand* value() { return inputs_[0]; }
-  LOperand* temp() { return temps_[0]; }
 
   DECLARE_CONCRETE_INSTRUCTION(MathPowHalf, "math-pow-half")
 };
@@ -1025,15 +1022,11 @@ class LCmpHoleAndBranch FINAL : public LControlInstruction<1, 0> {
 };
 
 
-class LCompareMinusZeroAndBranch FINAL : public LControlInstruction<1, 1> {
+class LCompareMinusZeroAndBranch FINAL : public LControlInstruction<1, 0> {
  public:
-  LCompareMinusZeroAndBranch(LOperand* value, LOperand* temp) {
-    inputs_[0] = value;
-    temps_[0] = temp;
-  }
+  explicit LCompareMinusZeroAndBranch(LOperand* value) { inputs_[0] = value; }
 
   LOperand* value() { return inputs_[0]; }
-  LOperand* temp() { return temps_[0]; }
 
   DECLARE_CONCRETE_INSTRUCTION(CompareMinusZeroAndBranch,
                                "cmp-minus-zero-and-branch")
@@ -1508,15 +1501,17 @@ class LAddI FINAL : public LTemplateInstruction<1, 2, 0> {
 };
 
 
-class LMathMinMax FINAL : public LTemplateInstruction<1, 2, 0> {
+class LMathMinMax FINAL : public LTemplateInstruction<1, 2, 1> {
  public:
-  LMathMinMax(LOperand* left, LOperand* right) {
+  LMathMinMax(LOperand* left, LOperand* right, LOperand* temp) {
     inputs_[0] = left;
     inputs_[1] = right;
+    temps_[0] = temp;
   }
 
   LOperand* left() { return inputs_[0]; }
   LOperand* right() { return inputs_[1]; }
+  LOperand* temp() { return temps_[0]; }
 
   DECLARE_CONCRETE_INSTRUCTION(MathMinMax, "math-min-max")
   DECLARE_HYDROGEN_ACCESSOR(MathMinMax)
@@ -2037,11 +2032,12 @@ class LCallRuntime FINAL : public LTemplateInstruction<1, 1, 0> {
   DECLARE_HYDROGEN_ACCESSOR(CallRuntime)
 
   virtual bool ClobbersDoubleRegisters(Isolate* isolate) const OVERRIDE {
-    return true;
+    return save_doubles() == kDontSaveFPRegs;
   }
 
   const Runtime::Function* function() const { return hydrogen()->function(); }
   int arity() const { return hydrogen()->argument_count(); }
+  SaveFPRegsMode save_doubles() const { return hydrogen()->save_doubles(); }
 };
 
 
@@ -2881,6 +2877,8 @@ class LChunkBuilder FINAL : public LChunkBuilderBase {
   LInstruction* DefineSameAsFirst(LTemplateResultInstruction<1>* instr);
   LInstruction* DefineFixed(LTemplateResultInstruction<1>* instr,
                             Register reg);
+  LInstruction* DefineFixed(LTemplateResultInstruction<1>* instr,
+                            X87Register reg);
   LInstruction* DefineX87TOS(LTemplateResultInstruction<1>* instr);
   // Assigns an environment to an instruction.  An instruction which can
   // deoptimize must have an environment.
index 66f5703..6f83f49 100644 (file)
@@ -148,8 +148,7 @@ void MacroAssembler::InNewSpace(
 
 void MacroAssembler::RememberedSetHelper(
     Register object,  // Only used for debug checks.
-    Register addr,
-    Register scratch,
+    Register addr, Register scratch, SaveFPRegsMode save_fp,
     MacroAssembler::RememberedSetFinalAction and_then) {
   Label done;
   if (emit_debug_code()) {
@@ -180,7 +179,7 @@ void MacroAssembler::RememberedSetHelper(
     DCHECK(and_then == kFallThroughAtEnd);
     j(equal, &done, Label::kNear);
   }
-  StoreBufferOverflowStub store_buffer_overflow(isolate(), kDontSaveFPRegs);
+  StoreBufferOverflowStub store_buffer_overflow(isolate(), save_fp);
   CallStub(&store_buffer_overflow);
   if (and_then == kReturnAtEnd) {
     ret(0);
@@ -191,6 +190,31 @@ void MacroAssembler::RememberedSetHelper(
 }
 
 
+void MacroAssembler::ClampTOSToUint8(Register result_reg) {
+  Label done, conv_failure;
+  sub(esp, Immediate(kPointerSize));
+  fnclex();
+  fist_s(Operand(esp, 0));
+  pop(result_reg);
+  X87CheckIA();
+  j(equal, &conv_failure, Label::kNear);
+  test(result_reg, Immediate(0xFFFFFF00));
+  j(zero, &done, Label::kNear);
+  setcc(sign, result_reg);
+  sub(result_reg, Immediate(1));
+  and_(result_reg, Immediate(255));
+  jmp(&done, Label::kNear);
+  bind(&conv_failure);
+  fnclex();
+  fldz();
+  fld(1);
+  FCmp();
+  setcc(below, result_reg);  // 1 if negative, 0 if positive.
+  dec_b(result_reg);         // 0 if negative, 255 if positive.
+  bind(&done);
+}
+
+
 void MacroAssembler::ClampUint8(Register reg) {
   Label done;
   test(reg, Immediate(0xFFFFFF00));
@@ -270,11 +294,8 @@ void MacroAssembler::LoadUint32NoSSE2(Register src) {
 
 
 void MacroAssembler::RecordWriteArray(
-    Register object,
-    Register value,
-    Register index,
-    RememberedSetAction remembered_set_action,
-    SmiCheck smi_check,
+    Register object, Register value, Register index, SaveFPRegsMode save_fp,
+    RememberedSetAction remembered_set_action, SmiCheck smi_check,
     PointersToHereCheck pointers_to_here_check_for_value) {
   // First, check if a write barrier is even needed. The tests below
   // catch stores of Smis.
@@ -294,8 +315,8 @@ void MacroAssembler::RecordWriteArray(
   lea(dst, Operand(object, index, times_half_pointer_size,
                    FixedArray::kHeaderSize - kHeapObjectTag));
 
-  RecordWrite(object, dst, value, remembered_set_action, OMIT_SMI_CHECK,
-              pointers_to_here_check_for_value);
+  RecordWrite(object, dst, value, save_fp, remembered_set_action,
+              OMIT_SMI_CHECK, pointers_to_here_check_for_value);
 
   bind(&done);
 
@@ -309,13 +330,9 @@ void MacroAssembler::RecordWriteArray(
 
 
 void MacroAssembler::RecordWriteField(
-    Register object,
-    int offset,
-    Register value,
-    Register dst,
-    RememberedSetAction remembered_set_action,
-    SmiCheck smi_check,
-    PointersToHereCheck pointers_to_here_check_for_value) {
+    Register object, int offset, Register value, Register dst,
+    SaveFPRegsMode save_fp, RememberedSetAction remembered_set_action,
+    SmiCheck smi_check, PointersToHereCheck pointers_to_here_check_for_value) {
   // First, check if a write barrier is even needed. The tests below
   // catch stores of Smis.
   Label done;
@@ -338,8 +355,8 @@ void MacroAssembler::RecordWriteField(
     bind(&ok);
   }
 
-  RecordWrite(object, dst, value, remembered_set_action, OMIT_SMI_CHECK,
-              pointers_to_here_check_for_value);
+  RecordWrite(object, dst, value, save_fp, remembered_set_action,
+              OMIT_SMI_CHECK, pointers_to_here_check_for_value);
 
   bind(&done);
 
@@ -352,11 +369,9 @@ void MacroAssembler::RecordWriteField(
 }
 
 
-void MacroAssembler::RecordWriteForMap(
-    Register object,
-    Handle<Map> map,
-    Register scratch1,
-    Register scratch2) {
+void MacroAssembler::RecordWriteForMap(Register object, Handle<Map> map,
+                                       Register scratch1, Register scratch2,
+                                       SaveFPRegsMode save_fp) {
   Label done;
 
   Register address = scratch1;
@@ -393,7 +408,8 @@ void MacroAssembler::RecordWriteForMap(
                       &done,
                       Label::kNear);
 
-  RecordWriteStub stub(isolate(), object, value, address, OMIT_REMEMBERED_SET);
+  RecordWriteStub stub(isolate(), object, value, address, OMIT_REMEMBERED_SET,
+                       save_fp);
   CallStub(&stub);
 
   bind(&done);
@@ -413,11 +429,8 @@ void MacroAssembler::RecordWriteForMap(
 
 
 void MacroAssembler::RecordWrite(
-    Register object,
-    Register address,
-    Register value,
-    RememberedSetAction remembered_set_action,
-    SmiCheck smi_check,
+    Register object, Register address, Register value, SaveFPRegsMode fp_mode,
+    RememberedSetAction remembered_set_action, SmiCheck smi_check,
     PointersToHereCheck pointers_to_here_check_for_value) {
   DCHECK(!object.is(value));
   DCHECK(!object.is(address));
@@ -461,8 +474,8 @@ void MacroAssembler::RecordWrite(
                 &done,
                 Label::kNear);
 
-  RecordWriteStub stub(isolate(), object, value, address,
-                       remembered_set_action);
+  RecordWriteStub stub(isolate(), object, value, address, remembered_set_action,
+                       fp_mode);
   CallStub(&stub);
 
   bind(&done);
@@ -707,6 +720,53 @@ void MacroAssembler::FCmp() {
 }
 
 
+void MacroAssembler::FXamMinusZero() {
+  fxam();
+  push(eax);
+  fnstsw_ax();
+  and_(eax, Immediate(0x4700));
+  // For minus zero, C3 == 1 && C1 == 1.
+  cmp(eax, Immediate(0x4200));
+  pop(eax);
+  fstp(0);
+}
+
+
+void MacroAssembler::FXamSign() {
+  fxam();
+  push(eax);
+  fnstsw_ax();
+  // For negative value (including -0.0), C1 == 1.
+  and_(eax, Immediate(0x0200));
+  pop(eax);
+  fstp(0);
+}
+
+
+void MacroAssembler::X87CheckIA() {
+  push(eax);
+  fnstsw_ax();
+  // For #IA, IE == 1 && SF == 0.
+  and_(eax, Immediate(0x0041));
+  cmp(eax, Immediate(0x0001));
+  pop(eax);
+}
+
+
+// rc=00B, round to nearest.
+// rc=01B, round down.
+// rc=10B, round up.
+// rc=11B, round toward zero.
+void MacroAssembler::X87SetRC(int rc) {
+  sub(esp, Immediate(kPointerSize));
+  fnstcw(MemOperand(esp, 0));
+  and_(MemOperand(esp, 0), Immediate(0xF3FF));
+  or_(MemOperand(esp, 0), Immediate(rc));
+  fldcw(MemOperand(esp, 0));
+  add(esp, Immediate(kPointerSize));
+}
+
+
 void MacroAssembler::AssertNumber(Register object) {
   if (emit_debug_code()) {
     Label ok;
@@ -844,8 +904,17 @@ void MacroAssembler::EnterExitFramePrologue() {
 }
 
 
-void MacroAssembler::EnterExitFrameEpilogue(int argc) {
-  sub(esp, Immediate(argc * kPointerSize));
+void MacroAssembler::EnterExitFrameEpilogue(int argc, bool save_doubles) {
+  // Optionally save FPU state.
+  if (save_doubles) {
+    // Store FPU state to m108byte.
+    int space = 108 + argc * kPointerSize;
+    sub(esp, Immediate(space));
+    const int offset = -2 * kPointerSize;  // entry fp + code object.
+    fnsave(MemOperand(ebp, offset - 108));
+  } else {
+    sub(esp, Immediate(argc * kPointerSize));
+  }
 
   // Get the required frame alignment for the OS.
   const int kFrameAlignment = base::OS::ActivationFrameAlignment();
@@ -859,7 +928,7 @@ void MacroAssembler::EnterExitFrameEpilogue(int argc) {
 }
 
 
-void MacroAssembler::EnterExitFrame() {
+void MacroAssembler::EnterExitFrame(bool save_doubles) {
   EnterExitFramePrologue();
 
   // Set up argc and argv in callee-saved registers.
@@ -868,17 +937,23 @@ void MacroAssembler::EnterExitFrame() {
   lea(esi, Operand(ebp, eax, times_4, offset));
 
   // Reserve space for argc, argv and isolate.
-  EnterExitFrameEpilogue(3);
+  EnterExitFrameEpilogue(3, save_doubles);
 }
 
 
 void MacroAssembler::EnterApiExitFrame(int argc) {
   EnterExitFramePrologue();
-  EnterExitFrameEpilogue(argc);
+  EnterExitFrameEpilogue(argc, false);
 }
 
 
-void MacroAssembler::LeaveExitFrame() {
+void MacroAssembler::LeaveExitFrame(bool save_doubles) {
+  // Optionally restore FPU state.
+  if (save_doubles) {
+    const int offset = -2 * kPointerSize;
+    frstor(MemOperand(ebp, offset - 108));
+  }
+
   // Get the return address from the stack and restore the frame pointer.
   mov(ecx, Operand(ebp, 1 * kPointerSize));
   mov(ebp, Operand(ebp, 0 * kPointerSize));
@@ -1908,8 +1983,8 @@ void MacroAssembler::IndexFromHash(Register hash, Register index) {
 }
 
 
-void MacroAssembler::CallRuntime(const Runtime::Function* f,
-                                 int num_arguments) {
+void MacroAssembler::CallRuntime(const Runtime::Function* f, int num_arguments,
+                                 SaveFPRegsMode save_doubles) {
   // If the expected number of arguments of the runtime function is
   // constant, we check that the actual number of arguments match the
   // expectation.
@@ -1921,7 +1996,7 @@ void MacroAssembler::CallRuntime(const Runtime::Function* f,
   // smarter.
   Move(eax, Immediate(num_arguments));
   mov(ebx, Immediate(ExternalReference(f, isolate())));
-  CEntryStub ces(isolate(), 1);
+  CEntryStub ces(isolate(), 1, save_doubles);
   CallStub(&ces);
 }
 
index 1fdca3c..17cd9f4 100644 (file)
@@ -74,8 +74,8 @@ class MacroAssembler: public Assembler {
   // at the address pointed to by the addr register.  Only works if addr is not
   // in new space.
   void RememberedSetHelper(Register object,  // Used for debug code.
-                           Register addr,
-                           Register scratch,
+                           Register addr, Register scratch,
+                           SaveFPRegsMode save_fp,
                            RememberedSetFinalAction and_then);
 
   void CheckPageFlag(Register object,
@@ -146,10 +146,8 @@ class MacroAssembler: public Assembler {
   // The offset is the offset from the start of the object, not the offset from
   // the tagged HeapObject pointer.  For use with FieldOperand(reg, off).
   void RecordWriteField(
-      Register object,
-      int offset,
-      Register value,
-      Register scratch,
+      Register object, int offset, Register value, Register scratch,
+      SaveFPRegsMode save_fp,
       RememberedSetAction remembered_set_action = EMIT_REMEMBERED_SET,
       SmiCheck smi_check = INLINE_SMI_CHECK,
       PointersToHereCheck pointers_to_here_check_for_value =
@@ -158,20 +156,14 @@ class MacroAssembler: public Assembler {
   // As above, but the offset has the tag presubtracted.  For use with
   // Operand(reg, off).
   void RecordWriteContextSlot(
-      Register context,
-      int offset,
-      Register value,
-      Register scratch,
+      Register context, int offset, Register value, Register scratch,
+      SaveFPRegsMode save_fp,
       RememberedSetAction remembered_set_action = EMIT_REMEMBERED_SET,
       SmiCheck smi_check = INLINE_SMI_CHECK,
       PointersToHereCheck pointers_to_here_check_for_value =
           kPointersToHereMaybeInteresting) {
-    RecordWriteField(context,
-                     offset + kHeapObjectTag,
-                     value,
-                     scratch,
-                     remembered_set_action,
-                     smi_check,
+    RecordWriteField(context, offset + kHeapObjectTag, value, scratch, save_fp,
+                     remembered_set_action, smi_check,
                      pointers_to_here_check_for_value);
   }
 
@@ -182,9 +174,7 @@ class MacroAssembler: public Assembler {
   // filters out smis so it does not update the write barrier if the
   // value is a smi.
   void RecordWriteArray(
-      Register array,
-      Register value,
-      Register index,
+      Register array, Register value, Register index, SaveFPRegsMode save_fp,
       RememberedSetAction remembered_set_action = EMIT_REMEMBERED_SET,
       SmiCheck smi_check = INLINE_SMI_CHECK,
       PointersToHereCheck pointers_to_here_check_for_value =
@@ -196,9 +186,7 @@ class MacroAssembler: public Assembler {
   // operation. RecordWrite filters out smis so it does not update the
   // write barrier if the value is a smi.
   void RecordWrite(
-      Register object,
-      Register address,
-      Register value,
+      Register object, Register address, Register value, SaveFPRegsMode save_fp,
       RememberedSetAction remembered_set_action = EMIT_REMEMBERED_SET,
       SmiCheck smi_check = INLINE_SMI_CHECK,
       PointersToHereCheck pointers_to_here_check_for_value =
@@ -207,11 +195,8 @@ class MacroAssembler: public Assembler {
   // For page containing |object| mark the region covering the object's map
   // dirty. |object| is the object being stored into, |map| is the Map object
   // that was stored.
-  void RecordWriteForMap(
-      Register object,
-      Handle<Map> map,
-      Register scratch1,
-      Register scratch2);
+  void RecordWriteForMap(Register object, Handle<Map> map, Register scratch1,
+                         Register scratch2, SaveFPRegsMode save_fp);
 
   // ---------------------------------------------------------------------------
   // Debugger Support
@@ -226,14 +211,14 @@ class MacroAssembler: public Assembler {
   // arguments in register eax and sets up the number of arguments in
   // register edi and the pointer to the first argument in register
   // esi.
-  void EnterExitFrame();
+  void EnterExitFrame(bool save_doubles);
 
   void EnterApiExitFrame(int argc);
 
   // Leave the current exit frame. Expects the return value in
   // register eax:edx (untouched) and the pointer to the first
   // argument in register esi.
-  void LeaveExitFrame();
+  void LeaveExitFrame(bool save_doubles);
 
   // Leave the current exit frame. Expects the return value in
   // register eax (untouched).
@@ -435,8 +420,13 @@ class MacroAssembler: public Assembler {
   // FCmp is similar to integer cmp, but requires unsigned
   // jcc instructions (je, ja, jae, jb, jbe, je, and jz).
   void FCmp();
+  void FXamMinusZero();
+  void FXamSign();
+  void X87CheckIA();
+  void X87SetRC(int rc);
 
   void ClampUint8(Register reg);
+  void ClampTOSToUint8(Register result_reg);
 
   void SlowTruncateToI(Register result_reg, Register input_reg,
       int offset = HeapNumber::kValueOffset - kHeapObjectTag);
@@ -717,14 +707,17 @@ class MacroAssembler: public Assembler {
   void StubReturn(int argc);
 
   // Call a runtime routine.
-  void CallRuntime(const Runtime::Function* f, int num_arguments);
-  // Convenience function: Same as above, but takes the fid instead.
-  void CallRuntime(Runtime::FunctionId id) {
+  void CallRuntime(const Runtime::Function* f, int num_arguments,
+                   SaveFPRegsMode save_doubles = kDontSaveFPRegs);
+  void CallRuntimeSaveDoubles(Runtime::FunctionId id) {
     const Runtime::Function* function = Runtime::FunctionForId(id);
-    CallRuntime(function, function->nargs);
+    CallRuntime(function, function->nargs, kSaveFPRegs);
   }
-  void CallRuntime(Runtime::FunctionId id, int num_arguments) {
-    CallRuntime(Runtime::FunctionForId(id), num_arguments);
+
+  // Convenience function: Same as above, but takes the fid instead.
+  void CallRuntime(Runtime::FunctionId id, int num_arguments,
+                   SaveFPRegsMode save_doubles = kDontSaveFPRegs) {
+    CallRuntime(Runtime::FunctionForId(id), num_arguments, save_doubles);
   }
 
   // Convenience function: call an external reference.
@@ -956,7 +949,7 @@ class MacroAssembler: public Assembler {
                       const CallWrapper& call_wrapper = NullCallWrapper());
 
   void EnterExitFramePrologue();
-  void EnterExitFrameEpilogue(int argc);
+  void EnterExitFrameEpilogue(int argc, bool save_doubles);
 
   void LeaveExitFrameEpilogue(bool restore_context);
 
index 17c49af..6cd33e5 100644 (file)
@@ -349,6 +349,7 @@ TEST(DisasmIa320) {
   __ fprem1();
   __ fincstp();
   __ ftst();
+  __ fxam();
   __ fxch(3);
   __ fld_s(Operand(ebx, ecx, times_4, 10000));
   __ fstp_s(Operand(ebx, ecx, times_4, 10000));
@@ -378,6 +379,12 @@ TEST(DisasmIa320) {
   __ fninit();
   __ nop();
 
+  __ fldcw(Operand(ebx, ecx, times_4, 10000));
+  __ fnstcw(Operand(ebx, ecx, times_4, 10000));
+  __ fadd_d(Operand(ebx, ecx, times_4, 10000));
+  __ fnsave(Operand(ebx, ecx, times_4, 10000));
+  __ frstor(Operand(ebx, ecx, times_4, 10000));
+
   // xchg.
   {
     __ xchg(eax, eax);