X87: enable the crankshaft compiler for X87 port.
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
This commit is contained in:
parent
ffd7362fcc
commit
45a7148678
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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(¬in);
|
||||
// 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);
|
||||
|
@ -45,7 +45,7 @@
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
bool CpuFeatures::SupportsCrankshaft() { return false; }
|
||||
bool CpuFeatures::SupportsCrankshaft() { return true; }
|
||||
|
||||
|
||||
static const byte kCallOpcode = 0xE8;
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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_;
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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()));
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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, ¬_minus_zero, Label::kNear);
|
||||
|
||||
if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
|
||||
// Check for negative zero.
|
||||
__ j(not_equal, ¬_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(¬_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, ¬_plus_0, Label::kNear); // NaN.
|
||||
__ j(not_equal, ¬_plus_0, Label::kNear);
|
||||
__ fldz();
|
||||
// FP data stack {base, exponent(TOS), zero}.
|
||||
__ faddp(2);
|
||||
__ bind(¬_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, ¬_zero_input);
|
||||
__ Move(result, Immediate(63)); // 63^31 == 32
|
||||
|
||||
__ bind(¬_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);
|
||||
|
@ -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);
|
||||
};
|
||||
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user